Matplotlib/PyPlot中的快速实时打印

Matplotlib/PyPlot中的快速实时打印,matplotlib,Matplotlib,多年来,我一直在努力在matplotlib中获得高效的实时绘图,直到今天我仍然不满意 我需要一个redraw\u figure函数,该函数更新图形“live”(在代码运行时),并在断点处停止时显示最新的绘图 下面是一些演示代码: import time from matplotlib import pyplot as plt import numpy as np def live_update_demo(): plt.subplot(2, 1, 1) h1 = plt.ims

多年来,我一直在努力在matplotlib中获得高效的实时绘图,直到今天我仍然不满意

我需要一个
redraw\u figure
函数,该函数更新图形“live”(在代码运行时),并在断点处停止时显示最新的绘图

下面是一些演示代码:

import time
from matplotlib import pyplot as plt
import numpy as np

def live_update_demo():

    plt.subplot(2, 1, 1)
    h1 = plt.imshow(np.random.randn(30, 30))
    redraw_figure()
    plt.subplot(2, 1, 2)
    h2, = plt.plot(np.random.randn(50))
    redraw_figure()

    t_start = time.time()
    for i in xrange(1000):
        h1.set_data(np.random.randn(30, 30))
        redraw_figure()
        h2.set_ydata(np.random.randn(50))
        redraw_figure()
        print 'Mean Frame Rate: %.3gFPS' % ((i+1) / (time.time() - t_start))

def redraw_figure():
    plt.draw()
    plt.pause(0.00001)

live_update_demo()
当代码运行时,绘图应该实时更新,并且在
redraw\u figure()之后的任何断点处停止时,我们应该看到最新的数据。问题是如何最好地实现
redraw\u figure()

在上面的实现中(
plt.draw();plt.pause(0.00001)
),它可以工作,但速度非常慢(~3.7FPS)

我可以这样做:

def redraw_figure():
    plt.gcf().canvas.flush_events()
    plt.show(block=False)
它运行得更快(~11FPS),但当您在断点处停止时,绘图不是最新的(例如,如果我在
t\u start=…
行上放置一个断点,则第二个绘图不会出现)

奇怪的是,真正起作用的是给这个节目打两次电话:

def redraw_figure():
    plt.gcf().canvas.flush_events()
    plt.show(block=False)
    plt.show(block=False)
这会产生11FPS,并且在任何一条线上中断时,都会使绘图与数据保持一致

现在我听说“block”关键字已被弃用。两次调用同一个函数似乎是一种奇怪的、可能是不可移植的黑客行为

那么,我可以在这个函数中加入什么,它将以合理的帧速率绘制,而不是一个巨大的混乱,并且最好能够跨后端和系统工作

一些注意事项:

  • 我在OSX上,使用
    TkAgg
    后端,但欢迎在任何后端/系统上使用解决方案
  • 交互模式“开启”将不起作用,因为它不会实时更新。当解释器等待用户输入时,它只是在Python控制台中更新
  • A建议执行:

    def redraw_图(): 图=plt.gcf() 图canvas.draw() 图canvas.flush_事件()

但至少在我的系统上,这根本不会重新绘制情节

所以,如果有人有答案,你会直接让我和成千上万的人非常高兴。他们的幸福感可能会渗透到他们的朋友和亲戚,以及他们的朋友和亲戚,等等,这样你就有可能改善数十亿人的生活。

结论
ImportantanceOfBeingernest展示了如何使用blit进行更快的绘图,但这并不像在
redraw\u figure
函数中添加不同的内容那样简单(您需要跟踪要重画的内容)

首先,问题中发布的代码在我的机器上以7 fps的速度运行,QT4Agg作为后端

现在,正如许多帖子所建议的,比如or,使用
blit
可能是一种选择。虽然提到blit会导致严重的内存泄漏,但我无法观察到这一点

我对你的代码做了一些修改,并比较了使用和不使用blit时的帧速率。下面的代码给出了

  • 在没有blit的情况下运行时为28 fps
  • 175 fps带blit
代码:


更新:
为了更快的绘制,可以考虑使用。 正如作者所说:“对于绘图,pyqtgraph不像matplotlib那样完整/成熟,但运行速度要快得多。”

我将上述示例移植到pyqtgraph。虽然它看起来有点难看,但在我的机器上,它以每秒250帧的速度运行

综上所述,

  • matplotlib(无间歇):每秒28帧
  • matplotlib(带间歇):175 fps
  • pyqtgraph:250 fps
pyqtgraph代码:

import sys
import time
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
import pyqtgraph as pg


class App(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(App, self).__init__(parent)

        #### Create Gui Elements ###########
        self.mainbox = QtGui.QWidget()
        self.setCentralWidget(self.mainbox)
        self.mainbox.setLayout(QtGui.QVBoxLayout())

        self.canvas = pg.GraphicsLayoutWidget()
        self.mainbox.layout().addWidget(self.canvas)

        self.label = QtGui.QLabel()
        self.mainbox.layout().addWidget(self.label)

        self.view = self.canvas.addViewBox()
        self.view.setAspectLocked(True)
        self.view.setRange(QtCore.QRectF(0,0, 100, 100))

        #  image plot
        self.img = pg.ImageItem(border='w')
        self.view.addItem(self.img)

        self.canvas.nextRow()
        #  line plot
        self.otherplot = self.canvas.addPlot()
        self.h2 = self.otherplot.plot(pen='y')


        #### Set Data  #####################

        self.x = np.linspace(0,50., num=100)
        self.X,self.Y = np.meshgrid(self.x,self.x)

        self.counter = 0
        self.fps = 0.
        self.lastupdate = time.time()

        #### Start  #####################
        self._update()

    def _update(self):

        self.data = np.sin(self.X/3.+self.counter/9.)*np.cos(self.Y/3.+self.counter/9.)
        self.ydata = np.sin(self.x/3.+ self.counter/9.)

        self.img.setImage(self.data)
        self.h2.setData(self.ydata)

        now = time.time()
        dt = (now-self.lastupdate)
        if dt <= 0:
            dt = 0.000000000001
        fps2 = 1.0 / dt
        self.lastupdate = now
        self.fps = self.fps * 0.9 + fps2 * 0.1
        tx = 'Mean Frame Rate:  {fps:.3f} FPS'.format(fps=self.fps )
        self.label.setText(tx)
        QtCore.QTimer.singleShot(1, self._update)
        self.counter += 1


if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    thisapp = App()
    thisapp.show()
    sys.exit(app.exec_())
导入系统 导入时间 从pyqtgraph.Qt导入QtCore、QtGui 将numpy作为np导入 将pyqtgraph作为pg导入 类应用程序(QtGui.QMainWindow): def uuu init uuu(self,parent=None): 超级(应用程序,自我)。\uuuuu初始化\uuuuuuuu(父级) ####创建Gui元素########### self.mainbox=QtGui.QWidget() self.setCentralWidget(self.mainbox) self.mainbox.setLayout(QtGui.QVBoxLayout()) self.canvas=pg.GraphicsLayoutWidget() self.mainbox.layout().addWidget(self.canvas) self.label=QtGui.QLabel() self.mainbox.layout().addWidget(self.label) self.view=self.canvas.addViewBox() self.view.setAspectLocked(True) self.view.setRange(QtCore.QRectF(0,01001100)) #图像打印 self.img=pg.ImageItem(border='w') self.view.addItem(self.img) self.canvas.nextRow() #线形图 self.otherplot=self.canvas.addPlot() self.h2=self.otherplot.plot(pen='y') ####设置数据##################### self.x=np.linspace(0,50,num=100) self.X,self.Y=np.meshgrid(self.X,self.X) self.counter=0 self.fps=0。 self.lastupdate=time.time() ####开始##################### 自我更新() def_更新(自): self.data=np.sin(self.X/3.+self.counter/9.)*np.cos(self.Y/3.+self.counter/9.) self.ydata=np.sin(self.x/3.+self.counter/9.) self.img.setImage(self.data) self.h2.setData(self.ydata) now=time.time() dt=(现在是self.lastupdate)
如果dt首先,问题中发布的代码在我的机器上以7fps的速度运行,以QT4Agg作为后端

现在,正如许多帖子所建议的,比如or,使用
blit
可能是一种选择。虽然提到blit会导致严重的内存泄漏,但我无法观察到这一点

我对你的代码做了一些修改,并比较了使用和不使用blit时的帧速率。下面的代码给出了

  • 在没有blit的情况下运行时为28 fps
  • 175 fps带blit
代码:


更新:
为了更快的绘制,可以考虑使用。 正如作者所说:“对于绘图,pyqtgraph不像matplotlib那样完整/成熟,但运行速度要快得多。”

我将上述示例移植到pyqtgraph。虽然它看起来有点难看,但在我的机器上,它以每秒250帧的速度运行

综上所述,

  • matplotlib(不带bli)
    import sys
    import time
    from pyqtgraph.Qt import QtCore, QtGui
    import numpy as np
    import pyqtgraph as pg
    
    
    class App(QtGui.QMainWindow):
        def __init__(self, parent=None):
            super(App, self).__init__(parent)
    
            #### Create Gui Elements ###########
            self.mainbox = QtGui.QWidget()
            self.setCentralWidget(self.mainbox)
            self.mainbox.setLayout(QtGui.QVBoxLayout())
    
            self.canvas = pg.GraphicsLayoutWidget()
            self.mainbox.layout().addWidget(self.canvas)
    
            self.label = QtGui.QLabel()
            self.mainbox.layout().addWidget(self.label)
    
            self.view = self.canvas.addViewBox()
            self.view.setAspectLocked(True)
            self.view.setRange(QtCore.QRectF(0,0, 100, 100))
    
            #  image plot
            self.img = pg.ImageItem(border='w')
            self.view.addItem(self.img)
    
            self.canvas.nextRow()
            #  line plot
            self.otherplot = self.canvas.addPlot()
            self.h2 = self.otherplot.plot(pen='y')
    
    
            #### Set Data  #####################
    
            self.x = np.linspace(0,50., num=100)
            self.X,self.Y = np.meshgrid(self.x,self.x)
    
            self.counter = 0
            self.fps = 0.
            self.lastupdate = time.time()
    
            #### Start  #####################
            self._update()
    
        def _update(self):
    
            self.data = np.sin(self.X/3.+self.counter/9.)*np.cos(self.Y/3.+self.counter/9.)
            self.ydata = np.sin(self.x/3.+ self.counter/9.)
    
            self.img.setImage(self.data)
            self.h2.setData(self.ydata)
    
            now = time.time()
            dt = (now-self.lastupdate)
            if dt <= 0:
                dt = 0.000000000001
            fps2 = 1.0 / dt
            self.lastupdate = now
            self.fps = self.fps * 0.9 + fps2 * 0.1
            tx = 'Mean Frame Rate:  {fps:.3f} FPS'.format(fps=self.fps )
            self.label.setText(tx)
            QtCore.QTimer.singleShot(1, self._update)
            self.counter += 1
    
    
    if __name__ == '__main__':
    
        app = QtGui.QApplication(sys.argv)
        thisapp = App()
        thisapp.show()
        sys.exit(app.exec_())
    
    import pyformulas as pf
    import matplotlib.pyplot as plt
    import numpy as np
    import time
    
    fig = plt.figure()
    
    screen = pf.screen(title='Plot')
    
    start = time.time()
    for i in range(10000):
        t = time.time() - start
    
        x = np.linspace(t-3, t, 100)
        y = np.sin(2*np.pi*x) + np.sin(3*np.pi*x)
        plt.xlim(t-3,t)
        plt.ylim(-3,3)
        plt.plot(x, y, c='black')
    
        # If we haven't already shown or saved the plot, then we need to draw the figure first...
        fig.canvas.draw()
    
        image = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
        image = image.reshape(fig.canvas.get_width_height()[::-1] + (3,))
    
        screen.update(image)
    
    #screen.close()