我正在尝试使用pylab进行blitting以快速帧速率为我的绘图制作动画;下面的代码似乎工作得很好,但是在旧的而不是重新绘制的基础上绘制新数据,这样我最终会得到一个数字填充行而不是一个动画行(在每个子图中)。任何以尽可能快的帧速率获得单个动画线(在每个子图中)的建议都非常受欢迎。
import pylab
import time
import threading
import random
import math
time_series, cos_series, sin_series = [], [], []
MAX = 100
# This generates new data for the plot
def data_generator():
while True:
time.sleep(0.1)
ts = time.time()
time_series.append(ts)
cos_series.append(math.sin( ts ))
sin_series.append(math.cos( ts ))
if len(cos_series) > MAX:
cos_series.pop(0)
if len(sin_series) > MAX:
sin_series.pop(0)
if len(time_series) > MAX:
time_series.pop(0)
if __name__ == '__main__':
# Run the receiving function in a separate thread.
thread = threading.Thread(target=data_generator)
thread.daemon = True
thread.start()
fig = pylab.figure()
ax = fig.add_subplot(211)
bx = fig.add_subplot(212)
ax.grid(True)
bx.grid(True)
print(len(time_series),len(sin_series),len(cos_series))
fig.show()
fig.canvas.draw()
line1, = ax.plot(time_series, sin_series, '-.k', animated=True)
line2, = bx.plot(time_series, cos_series, 'r+-', animated=True)
ax.legend(['Sin(x)'])
bx.legend(['Cos(x)'])
ax.set_ylim([-1,1])
bx.set_ylim([-1,1])
background_a = [fig.canvas.copy_from_bbox(ax.bbox)]
background_b = [fig.canvas.copy_from_bbox(bx.bbox)]
timer = 0
t_start = time.time()
# Continuously update plot
while True:
time.sleep(0.1)
line1.set_data(time_series,sin_series)
ax.set_xlim([time_series[0],time_series[-1]])
line2.set_data(time_series,cos_series)
bx.set_xlim([time_series[0],time_series[-1]])
ax.draw_artist(line1)
bx.draw_artist(line2)
fig.canvas.restore_region(background_a)
fig.canvas.restore_region(background_b)
fig.canvas.blit(ax.bbox)
fig.canvas.blit(bx.bbox)
timer += 1
print('FPS = ',timer/(time.time() - t_start))
答案 0 :(得分:2)
您的代码存在两个问题。
首先,当你这样做时:
background_a = [fig.canvas.copy_from_bbox(ax.bbox)]
background_b = [fig.canvas.copy_from_bbox(bx.bbox)]
你不应该把你的缓冲区对象放在一个列表中 - restore_region
只是直接获取缓冲区对象,所以你应该这样做:
background_a = fig.canvas.copy_from_bbox(ax.bbox)
background_b = fig.canvas.copy_from_bbox(bx.bbox)
其次,在渲染循环中,您需要在绘制任何更新的线条艺术家之前恢复背景,否则您将始终在移动线条上绘制背景。将这些行移到draw_artist
来电之上,如下所示:
fig.canvas.restore_region(background_a)
fig.canvas.restore_region(background_b)
ax.draw_artist(line1)
bx.draw_artist(line2)
fig.canvas.blit(ax.bbox)
fig.canvas.blit(bx.bbox)
现在一切都应该正常。
如果你想在动画过程中更新x轴,事情会变得复杂一些。首先,您需要将x轴设置为两组轴的动画:
ax = fig.add_subplot(211)
bx = fig.add_subplot(212)
ax.xaxis.set_animated(True)
bx.xaxis.set_animated(True)
轴边界框({{1}})不包含刻度标签,因此为了在渲染循环期间获得足够大的区域进行恢复,您需要缓存图形画布的较大区域,例如整个数字边界框:
ax.bbox
恢复背景:
figbackground = fig.canvas.copy_from_bbox(fig.bbox)
在每个时间点,您需要强制重新绘制x轴以及线条:
fig.canvas.restore_region(figbackground)
最后,当你进行blitting时,你需要使用包含刻度标签的轴剪辑框,而不是边界框,而不是:
ax.draw_artist(line1)
bx.draw_artist(line2)
ax.xaxis.draw(fig.canvas.renderer)
bx.xaxis.draw(fig.canvas.renderer)
通过这些更改,刻度标签和x网格线将得到更新,但到目前为止,我还没有弄清楚如何正确地绘制y网格线和图例。希望这能让你知道如何做到这一点。
同样tcaswell建议查看fig.canvas.blit(ax.clipbox)
fig.canvas.blit(bx.clipbox)
课程是正确的 - 对于你的情况,它可能会变得更简单,虽然我认为理解blitting如何工作也很好。