pyqtgraph滚动绘图:分块绘图,在当前窗口中仅显示最新的10s样本

2024-10-01 07:45:30 发布

您现在位置:Python中文网/ 问答频道 /正文

我在使用pygtgraph滚动绘图时遇到问题

预期结果

预期结果与pyqtgraph-examples-scrolling plots-plot5非常相似

X值是时间,可以通过简单的函数生成。Y值是随机值

每10秒采样一个区块,每个绘图最多可以有30秒的样本,这意味着3个区块当前绘图窗口仅显示最近10秒的样本

例如,现在总共有60秒的样本:

  • 50-60秒之间的数据将在当前窗口中查看
  • 使用鼠标向后拖动x轴,可以查看30秒到50秒之间的数据
  • 0-30秒之间的数据将不显示

我的代码

我当前的代码如下,它只能显示最新的30秒数据

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


win = pg.GraphicsLayoutWidget(show=True)
win.setWindowTitle('Scrolling Plots')

p1 = win.addPlot()
p1.setYRange(0,10)

xVal = [0]
yVal = [0]

def genTime():  # used to generate time
    t = 0
    while True:
        t += np.random.random_sample()
        yield t
        t = np.ceil(t)

xTime = genTime() 

#=====================================================

viewSize = 10   # current window show only latest 10s data
plotSize = 30   # plot 30s data -> 3 chunk
lstCurves = []  # List for Curves

def update():
    global p1, xVal, yVal, lstCurves

    #for c in lstCurves:
    #    c.setPos(xVal[-1], 0)

    i = np.ceil(xVal[-1]) % viewSize  # e.g. when time is 9.2s -> one 10s view size is full, append to curves list as one chunk
    if i == 0:
        curve = p1.plot()
        lstCurves.append(curve)
        xValLast = xVal[-1]
        yValLast = yVal[-1]

        xVal = [xValLast]
        yVal = [yValLast]

        while len(lstCurves) > 3:  # max 3 chunk (30 s)
            p1.removeItem(lstCurves.pop(0))  # remove the oldest 10s
        
    else:
        curve = lstCurves[-1]    # latest 10s curve
        
    xVal.append(next(xTime))
    yVal.append(random.randint(0,9))
    curve.setData(xVal, yVal)
    print(len(lstCurves))

    
#======================================================

timer = pg.QtCore.QTimer()
timer.timeout.connect(update)
timer.start(1000)


## Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
    import sys

    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

问题

我尝试过使用curve.setPos(xx, 0),看起来整个曲线都在沿x轴移动,但是x值和Y值之间的映射关系被破坏了

我还尝试使用setXRange()动态更改update()func中的x轴显示范围。但在这种情况下,我不能再使用鼠标将x轴拖回查看旧数据

我的英语不好,希望你能理解我的问题。如有任何建议,将不胜感激


Tags: 数据import绘图asnprandompyqtgraphpg
1条回答
网友
1楼 · 发布于 2024-10-01 07:45:30

问题

您的代码不执行所需操作的原因是:

  • 拖动以查看其他块时,禁用绘图的自动范围,之后,每次要查看新数据时都必须手动拖动绘图。此外,默认情况下,打印的自动范围将覆盖正在打印的所有数据
  • 当您在update函数中使用setRange()方法时,每次向数据添加另一个值时,它都会强制该范围。然后拖动将无法按您所需的方式工作

你能做什么

嗯,从我的角度来看,使用鼠标拖动来可视化其他数据不是很方便,我建议使用外部小部件来控制要查看的数据范围,例如,滑块、滚动条、旋转框等等。。。 一个QScrollBar可以完成这项工作,而且它在GUI中看起来很美观

在我的替代解决方案之前,我有一个建议:

  • 使用对象创建小部件、生成类并将变量用作属性,这样可以避免使用关键字global,并且可以将小部件用于其他目的

替代解决方案

试试这个:

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

class MyApp(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        ## Creating the Widgets and Layouts
        self.plot_widget = pg.PlotWidget()
        self.layout = QtGui.QVBoxLayout()
        self.sbutton = QtGui.QPushButton("Start / Continue")
        self.ebutton = QtGui.QPushButton("Stop")
        self.timer = pg.QtCore.QTimer()
        self.scroll = QtGui.QScrollBar(QtCore.Qt.Horizontal)
        ## Creating the variables and constants
        self.data = [[0], [random.randint(0,9)]]  ## [xVal, yVal] to create less variables
        self.plot_item = self.plot_widget.plot(*self.data)
        self.plot_widget.setYRange(0, 10)
        self.xTime = self.genTime()
        self.vsize = 10
        self.psize = 30
        ## Building the Widget
        self.setLayout(self.layout)
        self.layout.addWidget(self.sbutton)
        self.layout.addWidget(self.ebutton)
        self.layout.addWidget(self.plot_widget)
        self.layout.addWidget(self.scroll)
        ## Changing some properties of the widgets
        self.plot_widget.setMouseEnabled(x=False, y=False)
        self.ebutton.setEnabled(False)
        self.scroll.setEnabled(False)
        self.scroll.setMaximum(self.psize-self.vsize)
        self.scroll.setValue(self.psize-self.vsize)
        ## Coneccting the signals
        self.sbutton.clicked.connect(self.start)
        self.ebutton.clicked.connect(self.stop)
        self.timer.timeout.connect(self.update)
        self.scroll.valueChanged.connect(self.upd_scroll)

    def genTime(self):  # used to generate time
        t = 0
        while True:
            t += np.random.random_sample()
            yield t
            t = np.ceil(t)

    def upd_scroll(self):
        val = self.scroll.value()
        xmax = np.ceil(self.data[0][-1+self.vsize-self.psize+val])-1
        xmin = xmax-self.vsize
        self.plot_widget.setXRange(xmin, xmax)

    def update(self):
        num = len(self.data[0])
        if num <= self.psize:
            self.plot_item.setData(*self.data)
        else:
            self.plot_item.setData(
                self.data[0][-self.psize:],
                self.data[1][-self.psize:]
            )

        if num == self.vsize:
            self.scroll.setEnabled(True)
        self.data[0].append(next(self.xTime))
        self.data[1].append(random.randint(0,9))
        if num > self.vsize :
            self.upd_scroll()
     
    def start(self):
        self.sbutton.setEnabled(False)
        self.ebutton.setEnabled(True)
        self.timer.start(100)

    def stop(self):
        self.sbutton.setEnabled(True)
        self.ebutton.setEnabled(False)
        self.timer.stop()
        self.upd_scroll()
        
    def closeEvent(self, event):
        self.timer.stop()
        event.accept()

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = MyApp()
    window.show()
    sys.exit(app.exec_())

可能是这样的:

enter image description here

相关问题 更多 >