16

I am trying to save an animation I've created with the FuncAnimation class in Matplotlib. My animation is more complicated, but I get the same error when I try to save the simple example given here.

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation

pause = False
def simData():
    t_max = 10.0
    dt = 0.05
    x = 0.0
    t = 0.0
    while t < t_max:
        if not pause:
            x = np.sin(np.pi*t)
            t = t + dt
        yield x, t

def onClick(event):
    global pause
    pause ^= True

def simPoints(simData):
    x, t = simData[0], simData[1]
    time_text.set_text(time_template%(t))
    line.set_data(t, x)
    return line, time_text

fig = plt.figure()
ax = fig.add_subplot(111)
line, = ax.plot([], [], 'bo', ms=10) # I'm still not clear on this stucture...
ax.set_ylim(-1, 1)
ax.set_xlim(0, 10)

time_template = 'Time = %.1f s'    # prints running simulation time
time_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)
fig.canvas.mpl_connect('button_press_event', onClick)
ani = animation.FuncAnimation(fig, simPoints, simData, blit=False, interval=10,
    repeat=True)
plt.show()

However, when I try to save this animation by adding the line

ani.save('test.mp4')

at the end, only the first 100 frames are saved.

After the animation is saved, the function restarts and displays as expected, displaying and updating the figure 200 times (or until t reaches t_max, whatever I set that to be). But the movie that is saved only contains the first 100 frames.

The pause functionality makes it tricky. Without it I could just put in frames = 200 into the FuncAnimation call rather that using the iterator/generator type function I currently have for the frames argument. But by just putting in frames = 200, the frame count seems to be un-pauseable.

How can I fix this?

Community
  • 1
  • 1
hm8
  • 1,381
  • 3
  • 21
  • 41

1 Answers1

21
ani = animation.FuncAnimation(fig, simPoints, simData, blit=False, interval=10,
                              repeat=True, save_count=200)  

will solve the ploblem.

Internally, save only saves a fixed number of frames. If you pass in a fixed length sequence or a number, mpl can correctly guess the length. If you pass in a (possibly infinite) generator and do not pass in save_count it defaults to 100.

tacaswell
  • 84,579
  • 22
  • 210
  • 199
  • 1
    I am doing a very similar with the pause and start on the animation and by default it starts paused. When i put the save method after the FuncAnimation call and start the plotting it doesn't seem to render anything or save the frames. I was using imagemagick, also i am using a generator for plotting the data so i won't have a save_count. – bretcj7 Jun 16 '17 at 14:54
  • 2
    You can use `save_count=sys.maxsize` if you don't know the size ahead of time, at least for `.mp4` export – Stanley Bak Aug 21 '18 at 19:11
  • thanks @StanleyBak the `sys.maxsize` solved the problem. But while constantly saving the plot to a mp4 file, the inline graph stopped updating its animation. Do we have a fix for it? – Franva Apr 28 '21 at 05:23