I want to make an animated barchart in Python and save this animation in mp4 format. My problem is that the frames in the saved video overlay, although I use \"blit=True\" t
The problem you have here is that you create a new barplot in every interation of the animation. They will one by one be added to the plot, but since their height is shrinking over time, it may look as though only the first bar is present.
There are two ways to overcome this. First option is to clear the axes before plotting a new bar plot. This however will rescale the axis limits, which should then be constantly set to the same value.
The other option is to manipultate the one and only bar plot in the axes and adapt it's height for every frame. This is shown in the code below.
import matplotlib.pyplot as plt
from matplotlib import animation
def barlist(n):
return [1/float(n*k) for k in range(1,6)]
fig=plt.figure()
n=100 #Number of frames
x=range(1,6)
barcollection = plt.bar(x,barlist(1))
def animate(i):
y=barlist(i+1)
for i, b in enumerate(barcollection):
b.set_height(y[i])
anim=animation.FuncAnimation(fig,animate,repeat=False,blit=False,frames=n,
interval=100)
anim.save('mymovie.mp4',writer=animation.FFMpegWriter(fps=10))
plt.show()
Blitting is a technique where all the parts of the figure which do not change are stored as a background. Then for each animated frame, only the changing parts are redrawn. This avoids the background to be redrawn from scratch and thus allows for much faster animations. Blitting will only affect the on-screen animation, because saving the animation to a file is not performed in real-time (and doesn't need to anyways).
Using blit=False
here allows to make the code more simple because we do not need to care about the differences between the animation on screen and the one saved - they are just the same.
The enumerate
function yields both the index as well as the object from the enumerated sequence. I did use it here, because it is a convenient way to obtain both in the same loop. It is not at all important here, you could alternatively do something like
for i in range(len(barcollection)):
barcollection[i].set_height(y[i])