Python Pyqtgraph类:如何从数据缓冲区自动更新图形值?
我正在使用Python Pyqtgraph类:如何从数据缓冲区自动更新图形值?,python,graph,pyqtgraph,graph-visualization,Python,Graph,Pyqtgraph,Graph Visualization,我正在使用pyqtgraph模块制作一个漂亮而简单的实时图形。我想让它成为一个类/对象,可以接收数据缓冲区,在更新时,重新读取数据缓冲区以绘制图形。我在从类代码外部获取数据缓冲区值到对象中时遇到一些问题 代码如下: import pyqtgraph as pg # pip install pyqtgraph class App(QtGui.QMainWindow): def __init__(self, buffer_size, data_buffer, graph_title, p
pyqtgraph
模块制作一个漂亮而简单的实时图形。我想让它成为一个类/对象,可以接收数据缓冲区,在更新时,重新读取数据缓冲区以绘制图形。我在从类代码外部获取数据缓冲区值到对象中时遇到一些问题
代码如下:
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()
将pyqtgraph导入为pg
#pip安装pyqtgraph
类应用程序(QtGui.QMainWindow):
def uuu init uuuuu(自身、缓冲区大小、数据缓冲区、图形标题、父项=无):
超级(应用程序,自我)。\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.numDstreams=1
self.bufferLength=缓冲区大小
self.dataBuffer=数据缓冲区
self.graphTitle=图形标题
self.otherplot=[[self.canvas.addPlot(row=i,col=0,title=self.graphTitle)]\
对于范围内的i(0,self.numDstreams)]
self.h2=[[self.otherplot[i][0]。范围(0,self.numDstreams)]#,self.otherplot[i][1]内的i的plot(pen='r')],plot(pen='g'),self.otherplot[i][2]。plot(pen b')
self.ydata=[[np.zeros((1,self.bufferLength))]表示范围(0,self.numDstreams)]#内的i,np.zeros((1,self.bufferLength)),np.zeros((1,self.bufferLength))
对于范围内的i(0,self.numDstreams):
self.otherplot[i][0].setYRange(最小值=-100,最大值=100)
self.counter=0
self.fps=0。
self.lastupdate=time.time()
####开始#####################
自我更新()
def_更新(自):
对于范围内的i(0,self.numDstreams):
self.ydata[i][0]=np.array(self.dataBuffer)
self.h2[i][0].setData(self.ydata[i][0])
now=time.time()
dt=(现在是self.lastupdate)
如果注释中的dt,请指出您的计算不正确,因此我将从我的答案中删除\u update()
方法
说到这一点,方法exec\uz()
创建了一个事件循环,该循环在概念上为while True,因此在该行之后不会执行其他代码行,因此,while 1:
中的代码永远不会执行
另一方面,如果我们消除它,我们就不能将而1:
放在GUI线程内,因为它会阻止它,并且不允许GUI查看各种事件或更新GUI(例如绘制任务)
另外,如果您使用test\u 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_())
在注释中,指出您的计算不正确,因此我将从我的答案中删除
\u update()
方法
说到这一点,方法exec\uz()
创建了一个事件循环,该循环在概念上为while True,因此在该行之后不会执行其他代码行,因此,while 1:中的代码永远不会执行
另一方面,如果我们消除它,我们就不能将而1:
放在GUI线程内,因为它会阻止它,并且不允许GUI查看各种事件或更新GUI(例如绘制任务)
另外,如果您使用test\u 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_())
您可以更好地解释自己,您希望
test\u buffer=np.random.randn(100,)app.\u update()
更新图形?是的,这就是我希望发生的事情,我要补充一个问题。您希望它多久更新一次?图形模块的Pyqt
速度非常快,基本上,更新循环每秒读取数百帧,然后重新绘制。所以尽可能快。好的,我理解你,但不要期望超过60FPS,你的FPS计算是不正确的,你只是计算函数执行的时间_update(),这并不保证打印时的绘制速度是300FPS,如果没有必要,Qt和所有库图形不会自动更新视图,例如,60FPS为16.6ms,假设您仅以2ms的间隔放置数据,则每8个数据中仅显示1个。我可以让它更新,但我指出你的计算是不真实的。你可以更好地解释自己,你期望test\u buffer=np.random.randn(100,)app.\u update()
更新图表?是的,这就是我希望发生的事情,我要补充一个问题。您希望它多久更新一次?Pyqt图形模块非常快,基本上更新循环每秒读取数百帧,然后重新绘制。所以尽可能快。好的,我理解你,但不要期望超过60FPS,你的FPS计算是不正确的,你只是计算函数执行的时间_update(),这并不保证打印时的绘制速度是300FPS,如果没有必要,Qt和所有库图形不会自动更新视图,例如,60FPS为16.6ms,假设您仅以2ms的间隔放置数据,则每8个数据中仅显示1个。我可以让它更新,但我表明你的计算是不真实的。谢谢你的全面回答,我