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?
To save an animation, we can use Animation. save() or Animation.
interval: It is an optional integer value that represents the delay between each frame in milliseconds. Its default is 100. repeat_delay: It is an optional integer value that adds a delay in milliseconds before repeating the animation. It defaults to None.
blit=True means only re-draw the parts that have changed. anim = animation.FuncAnimation(fig, animate, init_func=init, frames=200, interval=20, blit=True) plt.show()
Alternatively you may stop the animation with anim. event_source. stop() . In order to have access to the animation inside the animating function one may use a class and make the animation a class variable.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With