Python中的动画条形图

时间:2017-02-05 19:35:02

标签: python-2.7 matplotlib bar-chart

我想在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设置每个帧的每个条的高度。但正如我所说,我真的不知道上面的例子中有什么问题。谢谢你的帮助!

马丁

1 个答案:

答案 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])