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

Posted

技术标签:

【中文标题】pyqtgraph 滚动图:分块绘图,在当前窗口中仅显示最新的 10 秒样本【英文标题】:pyqtgraph scrolling plots: plot in chunks, show only latest 10s samples in current window 【发布时间】:2021-03-27 15:59:25 【问题描述】:

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

预期结果

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

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

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

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

50s-60s之间的数据会在当前窗口查看 30s-50s之间的数据可以通过鼠标向后拖动x轴来查看 0-30s之间的数据不会显示

我的代码

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

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轴来查看旧数据了。

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

【问题讨论】:

真的需要用鼠标拖动来选择视图吗?或者它可以是,例如,一个滑块?。 【参考方案1】:

问题

您的代码不符合您的要求的原因是:

当您拖动查看其他块时,您禁用了绘图的自动自动范围,之后,您每次想要查看新数据时都必须手动拖动绘图。此外,默认情况下,绘图的自动范围将覆盖您正在绘制的所有数据。 当您在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_())

它可能看起来像这样:

【讨论】:

很高兴再次见到你,很有帮助。

以上是关于pyqtgraph 滚动图:分块绘图,在当前窗口中仅显示最新的 10 秒样本的主要内容,如果未能解决你的问题,请参考以下文章

移动到 QGraphicsView 时创建没有窗口打开和关闭的 pyqtgraph 图

防止创建绘图窗口 - Pyqtgraph plot

pyqtgraph绘图如何使用pyqtgraph

在线程内更新 pyqtgraph BarGraphItem

如何在pyqtgraph中缩放绘图

pyqtgraph:具有与 matplotlib drawstyle 类似功能的绘图