Python中的动画条形图

Mar*_*ath 3 matplotlib bar-chart python-2.7

我想在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()
Run Code Online (Sandbox Code Playgroud)

我必须承认,我不太清楚我应该做些什么来消除这个缺陷.我所知道的唯一的例子是条形图没有叠加在框架中(更确切地说,我指的是以下链接的第一个答案的代码):

动态更新matplotlib中的条形图

似乎我不得不告诉动画如何使用set_height-method设置每个帧的每个条的高度.但正如我所说,我真的不知道上面的例子中有什么问题.谢谢你的帮助!

马丁

Imp*_*est 9

您在这里遇到的问题是您在动画的每个交互中创建一个新的条形图.它们将逐一添加到图中,但由于它们的高度随着时间的推移而缩小,所以看起来好像只有第一个条形图存在.

有两种方法可以解决这个问题.第一个选项是在绘制新条形图之前清除轴.然而,这将重新调整轴限制,然后应该不断地将其设置为相同的值.

另一种选择是操纵轴上唯一的条形图并调整每个框架的高度.这显示在下面的代码中.

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()
Run Code Online (Sandbox Code Playgroud)


评论中的问题答案:

Blitting是一种技术,其中图中不变化的所有部分都存储为背景.然后,对于每个动画帧,仅重绘更改的部分.这避免了从头开始重绘背景,从而允许更快的动画.Blitting只会影响屏幕上的动画,因为将动画保存到文件中并不是实时执行的(并且无论如何都不需要).在这里
使用blit=False允许使代码更简单,因为我们不需要关心屏幕上的动画和保存的动画之间的差异 - 它们是相同的.

enumerate函数从枚举序列中生成索引和对象.我在这里使用它,因为它是在同一循环中获得两者的便捷方式.在这里一点都不重要,你也可以这样做

for i in range(len(barcollection)):
    barcollection[i].set_height(y[i])
Run Code Online (Sandbox Code Playgroud)