在Python中为直方图设置动画

时间:2013-08-19 18:05:49

标签: python animation histogram

我正在尝试随着时间的推移制作直方图动画,到目前为止我的代码是以下代码:

import matplotlib.pyplot as plt
import numpy as np
import time
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)

alphab = ['A', 'B', 'C', 'D', 'E', 'F']
frequencies = [1, 44, 12, 11, 2, 10]

pos = np.arange(len(alphab))
width = 1.0     # gives histogram aspect to the bar diagram
ax.set_xticks(pos + (width / 2))
ax.set_xticklabels(alphab)
for bin_idx in np.linspace(0,1000000,100000000):
     t = time.time()
     #Here we just change the first bin, so it increases through the animation.
     frequencies[0] = bin_idx
     line1 =plt.bar(pos, frequencies, width, color='r')
     plt.draw()
     elapsed = time.time() - t
     print elapsed

代码可以工作,但是输出显示了在一些迭代之后它变得比开始时慢得多。有没有办法加快速度,我们希望实时更新它,并且它运行的过程非常快。

另外,重要的是要注意,我不想要后处理动画,我们想要实时更新,因此直方图动画示例不适用于此特定过程。

由于

2 个答案:

答案 0 :(得分:3)

如果您有更新版本的Matplotlib,则有一个animations.FuncAnimation class可以帮助减少一些样板代码。 (See this page为例。)它非常快(〜每秒52帧):

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import timeit

clock = timeit.default_timer

fig, ax = plt.subplots()

alphab = ['A', 'B', 'C', 'D', 'E', 'F']
frequencies = [1, 44, 12, 11, 2, 10]

pos = np.arange(len(alphab))
width = 1.0     # gives histogram aspect to the bar diagram
ax.set_xticks(pos + (width / 2))
ax.set_xticklabels(alphab)

rects = plt.bar(pos, frequencies, width, color='r')
start = clock()

def animate(arg, rects):
    frameno, frequencies = arg
    for rect, f in zip(rects, frequencies):
        rect.set_height(f)
    print("FPS: {:.2f}".format(frameno / (clock() - start))) 

def step():
    for frame, bin_idx in enumerate(np.linspace(0,1000000,100000000), 1):
        #Here we just change the first bin, so it increases through the animation.
        frequencies[0] = bin_idx
        yield frame, frequencies


ani = animation.FuncAnimation(fig, animate, step, interval=10,
                              repeat=False, blit=False, fargs=(rects,))
plt.show()

如果您没有较新版本的Matplotlib,这是较旧的方法。它稍慢(〜每秒45帧):

不要在循环的每次迭代中调用plt.bar。相反,只需调用一次,保存rects返回值,然后调用set_height以在循环的后续迭代中修改rects的高度。这个技巧(以及其他技巧)在Matplotlib Animations Cookbook中解释。

import sys
import matplotlib as mpl
mpl.use('TkAgg')  # do this before importing pyplot
import matplotlib.pyplot as plt
import numpy as np
import timeit

clock = timeit.default_timer

fig, ax = plt.subplots()

alphab = ['A', 'B', 'C', 'D', 'E', 'F']
frequencies = [1, 44, 12, 11, 2, 10]

pos = np.arange(len(alphab))
width = 1.0     # gives histogram aspect to the bar diagram
ax.set_xticks(pos + (width / 2))
ax.set_xticklabels(alphab)

def animate():
    start = clock()
    rects = plt.bar(pos, frequencies, width, color='r')
    for frameno, bin_idx in enumerate(np.linspace(0,1000000,100000000), 2):
        #Here we just change the first bin, so it increases through the animation.
        frequencies[0] = bin_idx
        # rects = plt.bar(pos, frequencies, width, color='r')
        for rect, f in zip(rects, frequencies):
            rect.set_height(f)
        fig.canvas.draw()
        print("FPS: {:.2f}".format(frameno / (clock() - start)))         

win = fig.canvas.manager.window
win.after(1, animate)
plt.show()

为了进行比较,将plt.clf添加到原始代码中,在我的计算机上达到每秒12帧


关于时间的一些评论:

通过计算每次通过循环的非常小的时间差,您将无法获得准确的测量结果。 time.time()的时间分辨率 - 至少在我的计算机上 - 还不够。通过测量一个开始时间并计算开始时间和当前时间之间的大时间差,然后除以帧数,您将获得更准确的测量结果。

我还将time.time更改为timeit.default_timer。这两个在Unix计算机上是相同的,但在Windows机器上timeit.default_timer设置为time.clock。因此timeit.default_timer为每个平台选择更准确的计时器。

答案 1 :(得分:1)

我认为你的代码变慢了,因为你没有清除数字,所以你每次迭代都会重新绘制直方图。

plt.clf()清除现有图表之前添加line1 = ...来电。