Python - 带有子图的 blit 只绘制最后的子图 [英] Python - blit with subplots only plotting last subplots
问题描述
我正在尝试在我的 Python 应用程序中实时绘制多个子图.理想情况下,我还应该能够在每个子图中绘制多条线,但为了简单起见,我假设每个子图中有一条线.为了有效地做到这一点(我正在寻找快速绘图),我试图扩展一个我在网上找到的示例(
我是python的新手,我想这是一个非常愚蠢的问题,但是我还没有弄清楚,所以每个提示对我都非常有帮助.谢谢
在当前实现中,您仅设置最后一个绘图的轴限制,即 plt.axis([xmin,xmax,ymin,ymax])
适用于最后一个活动子图.
相反,您需要将所有轴 ax1
更新为 ax4
,
ax1.axis([xmin, xmax, ymin, ymax])ax2.axis([xmin, xmax, ymin, ymax])ax3.axis([xmin, xmax, ymin, ymax])ax4.axis([xmin, xmax, ymin, ymax])
让其限制遵循数据.
另外,似乎可以在不出现blitting条件的情况下更新数据,以便可以比较blitting而不会进行blitting.
完整代码:
导入时间导入 matplotlibmatplotlib.use('TkAgg')导入 matplotlib.pylab 作为 plt随机导入def test_fps(use_blit = True):ax1.cla()ax1.set_title('传感器输入 vs. 时间 -')ax1.set_xlabel('时间(s)')ax1.set_ylabel('传感器输入(mV)')ax2.cla()ax2.set_title('传感器输入与时间-')ax2.set_xlabel('时间(s)')ax2.set_ylabel('传感器输入(mV)')ax3.cla()ax3.set_title('传感器输入与时间-')ax3.set_xlabel('时间(s)')ax3.set_ylabel('传感器输入(mV)')ax4.cla()ax4.set_title('传感器输入 vs. 时间 -')ax4.set_xlabel('时间(s)')ax4.set_ylabel('传感器输入(mV)')plt.ion() # 设置交互模式为 ON,这样 matplotlib 就不会阻塞窗口plt.show(False)#设置为false以便代码不会在此处停止cur_time = time.time()# ax1.hold(真)# ax2.hold(真)# ax3.hold(真)#ax4.hold(真)x,y = [],[]times = [time.time()-cur_time]#创建空白数组以保存时间值y.append(0)line1,= ax1.plot(times,y,'.-',alpha = 0.8,color ="gray",markerfacecolor ="red")line2,= ax2.plot(times,y,'.-',alpha = 0.8,color ="gray",markerfacecolor ="red")line3, = ax3.plot(times, y, '.-', alpha=0.8, color="gray", markerfacecolor="red")line4,= ax4.plot(times,y,'.-',alpha = 0.8,color ="gray",markerfacecolor ="red")图.show()fig.canvas.draw()如果使用_blit:background1 = fig.canvas.copy_from_bbox(ax1.bbox)#缓存背景background2 = fig.canvas.copy_from_bbox(ax2.bbox)#缓存背景background3 = fig.canvas.copy_from_bbox(ax3.bbox) # 缓存背景background4 = fig.canvas.copy_from_bbox(ax4.bbox)#缓存背景tic = time.time()硝 = 200我= 0而我<硝:字段 = random.random() * 100times.append(time.time() - cur_time)y.append(字段)# 这会删除数据的尾部,因此您可以长时间运行.你可以缓存这个# 并将其并行存储在pickle变量中.如果len(times)>50:删除 [0]删除时间[0]xmin,xmax,ymin,ymax = [min(times)/1.05,max(times)* 1.1,-5,110]#将新数据输入绘图并再次设置轴限制ax1.axis([xmin,xmax,ymin,ymax])ax2.axis([xmin,xmax,ymin,ymax])ax3.axis([xmin,xmax,ymin,ymax])ax4.axis([xmin,xmax,ymin,ymax])line1.set_data(times, y)line2.set_data(times, y)line3.set_data(times,y)line4.set_data(times,y)如果use_blit:fig.canvas.restore_region(background1)#恢复背景ax1.draw_artist(line1)#重画点fig.canvas.blit(ax1.bbox) # 填充坐标轴矩形fig.canvas.restore_region(background2)#恢复背景ax2.draw_artist(line2) # 只重绘点fig.canvas.blit(ax2.bbox)fig.canvas.restore_region(background3)#恢复背景ax3.draw_artist(line3)#重画点fig.canvas.blit(ax3.bbox)fig.canvas.restore_region(background4)#恢复背景ax4.draw_artist(line4)#重画点fig.canvas.blit(ax4.bbox)别的:fig.canvas.draw()fig.canvas.flush_events()我 += 1fps = niter/(time.time() - tic)返回fps无花果= plt.figure()ax1 = fig.add_subplot(4,1,1)ax2 = fig.add_subplot(4, 1, 2)ax3 = fig.add_subplot(4, 1, 3)ax4 = fig.add_subplot(4, 1, 4)fps1 = test_fps(use_blit=True)打印fps1
请注意,此命令在我的计算机上运行时不会出现10 fps的闪烁,而会以16 fps的速度闪烁.
I am trying to plot multiple subplots in real-time in my python application. Ideally, I should also be able to plot multiple lines in each subplot, but for simplicity here I assume one line per subplot. In order to do so efficiently (I am looking for fast plots), I am trying to extend one example I found online (https://taher-zadeh.com/speeding-matplotlib-plotting-times-real-time-monitoring-purposes/) to my case. My code is:
import time
# for Mac OSX
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pylab as plt
import random
def test_fps(use_blit=True):
ax1.cla()
ax1.set_title('Sensor Input vs. Time -')
ax1.set_xlabel('Time (s)')
ax1.set_ylabel('Sensor Input (mV)')
ax2.cla()
ax2.set_title('Sensor Input vs. Time -' )
ax2.set_xlabel('Time (s)')
ax2.set_ylabel('Sensor Input (mV)')
ax3.cla()
ax3.set_title('Sensor Input vs. Time -')
ax3.set_xlabel('Time (s)')
ax3.set_ylabel('Sensor Input (mV)')
ax4.cla()
ax4.set_title('Sensor Input vs. Time -')
ax4.set_xlabel('Time (s)')
ax4.set_ylabel('Sensor Input (mV)')
plt.ion() # Set interactive mode ON, so matplotlib will not be blocking the window
plt.show(False) # Set to false so that the code doesn't stop here
cur_time = time.time()
ax1.hold(True)
ax2.hold(True)
ax3.hold(True)
ax4.hold(True)
x, y = [], []
times = [time.time() - cur_time] # Create blank array to hold time values
y.append(0)
line1, = ax1.plot(times, y, '.-', alpha=0.8, color="gray", markerfacecolor="red")
line2, = ax2.plot(times, y, '.-', alpha=0.8, color="gray", markerfacecolor="red")
line3, = ax3.plot(times, y, '.-', alpha=0.8, color="gray", markerfacecolor="red")
line4, = ax4.plot(times, y, '.-', alpha=0.8, color="gray", markerfacecolor="red")
fig.show()
fig.canvas.draw()
if use_blit:
background1 = fig.canvas.copy_from_bbox(ax1.bbox) # cache the background
background2 = fig.canvas.copy_from_bbox(ax2.bbox) # cache the background
background3 = fig.canvas.copy_from_bbox(ax3.bbox) # cache the background
background4 = fig.canvas.copy_from_bbox(ax4.bbox) # cache the background
tic = time.time()
niter = 200
i = 0
while i < niter:
fields = random.random() * 100
times.append(time.time() - cur_time)
y.append(fields)
# this removes the tail of the data so you can run for long hours. You can cache this
# and store it in a pickle variable in parallel.
if len(times) > 50:
del y[0]
del times[0]
xmin, xmax, ymin, ymax = [min(times) / 1.05, max(times) * 1.1, -5,110]
# feed the new data to the plot and set the axis limits again
plt.axis([xmin, xmax, ymin, ymax])
if use_blit:
fig.canvas.restore_region(background1) # restore background
line1.set_xdata(times)
line1.set_ydata(y)
ax1.draw_artist(line1) # redraw just the points
fig.canvas.blit(ax1.bbox) # fill in the axes rectangle
fig.canvas.restore_region(background2) # restore background
line2.set_xdata(times)
line2.set_ydata(y)
ax2.draw_artist(line2) # redraw just the points
fig.canvas.blit(ax2.bbox)
fig.canvas.restore_region(background3) # restore background
line3.set_xdata(times)
line3.set_ydata(y)
ax3.draw_artist(line3) # redraw just the points
fig.canvas.blit(ax3.bbox)
fig.canvas.restore_region(background4) # restore background
line4.set_xdata(times)
line4.set_ydata(y)
ax4.draw_artist(line4) # redraw just the points
fig.canvas.blit(ax4.bbox)
else:
fig.canvas.draw()
fig.canvas.flush_events()
i += 1
fps = niter / (time.time() - tic)
return fps
and
fig = plt.figure()
ax1 = fig.add_subplot(4, 1, 1)
ax2 = fig.add_subplot(4, 1, 2)
ax3 = fig.add_subplot(4, 1, 3)
ax4 = fig.add_subplot(4, 1, 4)
fps1 = test_fps(use_blit=True)
The problem with this code is that is only plotting onto the last subplots and Leaves the Others blank.
I am new to python and I guess this is a very silly question but I have not managed to figure it out yet so every hint would be very helpful to me. Thank you
In the current implementation you set the axis limits only for the last plot, i.e. plt.axis([xmin, xmax, ymin, ymax])
works on the last active subplot.
Instead you would need to update all of the axes ax1
to ax4
,
ax1.axis([xmin, xmax, ymin, ymax])
ax2.axis([xmin, xmax, ymin, ymax])
ax3.axis([xmin, xmax, ymin, ymax])
ax4.axis([xmin, xmax, ymin, ymax])
to let their limits follow the data.
Additionally it seems beneficial to update the data outside the blitting condition, such that one can compare blitting without blitting.
Complete code:
import time
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pylab as plt
import random
def test_fps(use_blit=True):
ax1.cla()
ax1.set_title('Sensor Input vs. Time -')
ax1.set_xlabel('Time (s)')
ax1.set_ylabel('Sensor Input (mV)')
ax2.cla()
ax2.set_title('Sensor Input vs. Time -' )
ax2.set_xlabel('Time (s)')
ax2.set_ylabel('Sensor Input (mV)')
ax3.cla()
ax3.set_title('Sensor Input vs. Time -')
ax3.set_xlabel('Time (s)')
ax3.set_ylabel('Sensor Input (mV)')
ax4.cla()
ax4.set_title('Sensor Input vs. Time -')
ax4.set_xlabel('Time (s)')
ax4.set_ylabel('Sensor Input (mV)')
plt.ion() # Set interactive mode ON, so matplotlib will not be blocking the window
plt.show(False) # Set to false so that the code doesn't stop here
cur_time = time.time()
# ax1.hold(True)
# ax2.hold(True)
# ax3.hold(True)
# ax4.hold(True)
x, y = [], []
times = [time.time() - cur_time] # Create blank array to hold time values
y.append(0)
line1, = ax1.plot(times, y, '.-', alpha=0.8, color="gray", markerfacecolor="red")
line2, = ax2.plot(times, y, '.-', alpha=0.8, color="gray", markerfacecolor="red")
line3, = ax3.plot(times, y, '.-', alpha=0.8, color="gray", markerfacecolor="red")
line4, = ax4.plot(times, y, '.-', alpha=0.8, color="gray", markerfacecolor="red")
fig.show()
fig.canvas.draw()
if use_blit:
background1 = fig.canvas.copy_from_bbox(ax1.bbox) # cache the background
background2 = fig.canvas.copy_from_bbox(ax2.bbox) # cache the background
background3 = fig.canvas.copy_from_bbox(ax3.bbox) # cache the background
background4 = fig.canvas.copy_from_bbox(ax4.bbox) # cache the background
tic = time.time()
niter = 200
i = 0
while i < niter:
fields = random.random() * 100
times.append(time.time() - cur_time)
y.append(fields)
# this removes the tail of the data so you can run for long hours. You can cache this
# and store it in a pickle variable in parallel.
if len(times) > 50:
del y[0]
del times[0]
xmin, xmax, ymin, ymax = [min(times) / 1.05, max(times) * 1.1, -5,110]
# feed the new data to the plot and set the axis limits again
ax1.axis([xmin, xmax, ymin, ymax])
ax2.axis([xmin, xmax, ymin, ymax])
ax3.axis([xmin, xmax, ymin, ymax])
ax4.axis([xmin, xmax, ymin, ymax])
line1.set_data(times, y)
line2.set_data(times, y)
line3.set_data(times, y)
line4.set_data(times, y)
if use_blit:
fig.canvas.restore_region(background1) # restore background
ax1.draw_artist(line1) # redraw just the points
fig.canvas.blit(ax1.bbox) # fill in the axes rectangle
fig.canvas.restore_region(background2) # restore background
ax2.draw_artist(line2) # redraw just the points
fig.canvas.blit(ax2.bbox)
fig.canvas.restore_region(background3) # restore background
ax3.draw_artist(line3) # redraw just the points
fig.canvas.blit(ax3.bbox)
fig.canvas.restore_region(background4) # restore background
ax4.draw_artist(line4) # redraw just the points
fig.canvas.blit(ax4.bbox)
else:
fig.canvas.draw()
fig.canvas.flush_events()
i += 1
fps = niter / (time.time() - tic)
return fps
fig = plt.figure()
ax1 = fig.add_subplot(4, 1, 1)
ax2 = fig.add_subplot(4, 1, 2)
ax3 = fig.add_subplot(4, 1, 3)
ax4 = fig.add_subplot(4, 1, 4)
fps1 = test_fps(use_blit=True)
print fps1
Just to note this runs without blitting at 10fps and with blitting at 16 fps on my computer.
这篇关于Python - 带有子图的 blit 只绘制最后的子图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!