我想在Python中制作动画条形图并以mp4格式保存此动画。我的问题是保存的视频覆盖中的帧,虽然我使用“blit = True”来告诉动画,只画出从帧到帧的变化。令人惊讶的是,在Python的内置预览中不会出现此问题。 这是一个反映我情况的最小值:
import matplotlib.pyplot as plt
from matplotlib import animation
def barlist(n): #That's the list of bars I want to display
C=[]
for k in range(1,6):
C.append(1/float(n*k))
return C
fig=plt.figure()
n=100 #Number of frames
def animate(i):
x=range(1,6)
y=barlist(i+1)
return plt.bar(x,y)
anim=animation.FuncAnimation(fig,animate,repeat=False,blit=True,frames=n,
interval=50)
anim.save('barchart_animated_'+str(n)+'.mp4')
plt.show()
我必须承认,我不确定应该怎样做才能消除这个漏洞。我所知道的唯一的例子是条形图没有叠加在框架中(更确切地说,我指的是以下链接的第一个答案的代码):
Dynamically updating a bar plot in matplotlib
似乎我不得不告诉动画如何使用set_height-method设置每个帧的每个条的高度。但正如我所说,我真的不知道上面的例子中有什么问题。谢谢你的帮助!
马丁
答案 0 :(得分:7)
您遇到的问题是您在动画的每个交互中创建一个新的条形图。它们将逐一添加到绘图中,但由于它们的高度随着时间的推移而缩小,所以看起来好像只有第一个柱子存在。
有两种方法可以解决这个问题。第一个选项是在绘制新条形图之前清除轴。然而,这将重新调整轴限制,然后应该不断地将其设置为相同的值。
另一种选择是操纵轴上唯一的条形图并调整每个框架的高度。这显示在下面的代码中。
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是一种技术,其中图中不变化的所有部分都存储为背景。然后,对于每个动画帧,仅重绘更改的部分。这避免了从头开始重绘背景,从而允许更快的动画。 Blitting只会影响屏幕上的动画,因为将动画保存到文件中并不是实时执行的(并且无论如何都不需要)。
在这里使用blit=False
可以使代码更简单,因为我们不需要关心屏幕上的动画与保存的动画之间的差异 - 它们是相同的。
enumerate
函数既可以生成索引,也可以从枚举序列中生成对象。我在这里使用它,因为它是在同一循环中获得两者的便捷方式。在这里一点也不重要,你可以选择做
for i in range(len(barcollection)):
barcollection[i].set_height(y[i])