Python - 带有子图的 blit 只绘制最后的子图 [英] Python - blit with subplots only plotting last subplots

查看:45
本文介绍了Python - 带有子图的 blit 只绘制最后的子图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在我的 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆