Pyqtgraph类:如何从数据缓冲区自动更新图形值?

时间:2018-06-13 20:14:49

标签: python graph pyqtgraph graph-visualization

我使用import pyqtgraph as pg # pip install pyqtgraph class App(QtGui.QMainWindow): def __init__(self, buffer_size, data_buffer, graph_title, 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)) self.numDstreams = 1 self.bufferLength = buffer_size self.dataBuffer = data_buffer self.graphTitle = graph_title self.otherplot = [[self.canvas.addPlot(row=i,col=0, title=self.graphTitle)] # , repeat line for more for i in range(0,self.numDstreams)] self.h2 = [[self.otherplot[i][0].plot(pen='r')] for i in range(0,self.numDstreams)] # , self.otherplot[i][1].plot(pen='g'), self.otherplot[i][2].plot(pen='b') self.ydata = [[np.zeros((1,self.bufferLength))] for i in range(0,self.numDstreams)] # ,np.zeros((1,self.bufferLength)),np.zeros((1,self.bufferLength)) for i in range(0,self.numDstreams): self.otherplot[i][0].setYRange(min= -100, max= 100) self.counter = 0 self.fps = 0. self.lastupdate = time.time() #### Start ##################### self._update() def _update(self): for i in range(0,self.numDstreams): self.ydata[i][0] = np.array(self.dataBuffer) self.h2[i][0].setData(self.ydata[i][0]) 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 def CreateGraph(buffer_size, data_buffer, graph_title): app1 = QtGui.QApplication(sys.argv) thisapp1 = App(buffer_size, data_buffer, graph_title) thisapp1.show() sys.exit(app1.exec_()) return app1 if __name__ == "__main__": test_buffer = np.random.randn(100,) app = CreateGraph(100, test_buffer, "Activity Score") while 1: test_buffer = np.random.randn(100,) app._update() 模块制作一个漂亮而简单的实时图表。我想把它作为一个可以接收数据缓冲区的类/对象,并在更新时重新读取数据缓冲区以绘制图形。我在从类代码外部获取数据缓冲区值到对象时遇到了一些麻烦。

以下代码:

test_buffer = np.random.randn(100,) app._update()

代码的工作原理是它绘制了随机数据的初始图形。但是,它不会像我想要的那样在循环中更新。当我使用这个对象时,我希望它能够根据外部变量更新其图形数据缓冲区,正如我正在尝试的那样。相反,它是堆叠的,即它只是第一次读取数据。

编辑 - 要清楚,我希望{{1}}能够在循环中连续更新图表。我需要图表能够实时读取缓冲变量并绘制新数据。

我有什么想法可以做到这一点?谢谢。

1 个答案:

答案 0 :(得分:1)

在评论中,指出您的计算不正确,因此我将从我的答案中删除_update()方法。

接下来,方法exec_()创建一个事件循环,概念上是一个True,以便在该行之后不执行任何其他代码行,因此来自while 1:的代码永远不会被执行

另一方面,如果我们消除它,我们就无法将while 1:置于GUI线程中,因为它会阻止它,并且不会让GUI查看各种事件或更新GUI,例如绘制任务。 / p>

此外,如果您使用test_buffer = np.random.randn(100,)并不意味着self.dataBuffer已更新,则不会将其链接。

解决方案是将while 1:置于新线程内,并通过信号将数据发送到主线程。

import sys

import threading

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


class App(QtGui.QMainWindow):
    def __init__(self, buffer_size=0, data_buffer=[], graph_title="", 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))

        self.numDstreams = 1
        self.bufferLength = buffer_size
        self.graphTitle = graph_title

        self.otherplot = [[self.canvas.addPlot(row=i,col=0, title=self.graphTitle)] # , repeat line for more
                           for i in range(0,self.numDstreams)]
        self.h2 = [[self.otherplot[i][0].plot(pen='r')] for i in range(0,self.numDstreams)] # , self.otherplot[i][1].plot(pen='g'), self.otherplot[i][2].plot(pen='b')
        self.ydata = [[np.zeros((1,self.bufferLength))] for i in range(0,self.numDstreams)] # ,np.zeros((1,self.bufferLength)),np.zeros((1,self.bufferLength))

        for i in range(0,self.numDstreams):
            self.otherplot[i][0].setYRange(min= -100, max= 100) 
        self.update_plot(data_buffer)

    def update_plot(self, data):
        self.dataBuffer = data
        for i in range(0, self.numDstreams):
            self.ydata[i][0] = np.array(self.dataBuffer)
            self.h2[i][0].setData(self.ydata[i][0])


def CreateGraph(graph_title): 
    thisapp1 = App(graph_title=graph_title)
    thisapp1.show()
    return thisapp1

class Helper(QtCore.QObject):
    bufferChanged = QtCore.pyqtSignal(object)

def generate_buffer(helper):
    while 1:
        test_buffer = np.random.randn(100,)
        helper.bufferChanged.emit(test_buffer)
        QtCore.QThread.msleep(1)

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)

    graph = CreateGraph("Activity Score")
    helper = Helper()
    threading.Thread(target=generate_buffer, args=(helper, ), daemon=True).start()
    helper.bufferChanged.connect(graph.update_plot)

    if sys.flags.interactive != 1 or not hasattr(QtCore, 'PYQT_VERSION'):
        sys.exit(app.exec_())