使用 pyqtgraph 和 PyQt5 的多个实时绘图 GUI

Multiple live plot GUI using pyqtgraph and PyQt5

我正在尝试创建一个带有多个实时绘图 EEG/ECG 图形的图形用户界面(每个绘图在不同的轴上)。 据我了解,我需要在网格布局中创建多个 PlotWidgets。

我使用 pyqtgraph 创建了一个实时绘图,但我不确定如何将其合并到 GUI 中:

从 pyqtgraph.Qt 导入 QtGui、QtCore 将 pyqtgraph 导入为 pg 导入集合 随机导入 导入时间 导入数学 将 numpy 导入为 np

class DynamicPlotter:

    def __init__(self, sampleinterval=0.1, timewindow=10., size=(600, 350)):
        # Data stuff
        self.interval = int(sampleinterval * 1000)
        self.bufsize = int(timewindow / sampleinterval)
        self.databuffer = collections.deque([0.0] * self.bufsize, self.bufsize)
        self.x = np.linspace(-timewindow, 0.0, self.bufsize)
        self.y = np.zeros(self.bufsize, dtype=float)
        # PyQtGraph stuff
        self.app = QtGui.QApplication([])
        self.plt = pg.plot(title='EEG/ECG Live Plot')
        self.plt.resize(*size)
        self.plt.showGrid(x=True, y=True)
        #self.plt.setXRange(5,20, padding=0)
        self.plt.setLabel('left', 'Amplitude', 'uVrms')
        self.plt.setLabel('bottom', 'Time', 's')
        self.curve = self.plt.plot(self.x, self.y, pen=(255, 0, 0))

        # QTimer
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.updateplot)
        self.timer.start(self.interval)

    def getdata(self):
        frequency = 0.5
        noise = random.normalvariate(0., 1.)
        new = 10. * math.sin(time.time() * frequency * 2 * math.pi) + noise
        return new

    def updateplot(self):
        self.databuffer.append(self.getdata())
        self.y[:] = self.databuffer
        self.curve.setData(self.x, self.y)
        self.app.processEvents()

    def run(self):
        self.app.exec_()

if __name__ == '__main__':
    livePlot = DynamicPlotter(sampleinterval=0.05, timewindow=5.)
    livePlot.run()

这是基本的 GUI(网格内有 3 个绘图小部件,主窗口中有一些标签):

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(845, 727)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.labelTitle = QtWidgets.QLabel(self.centralwidget)
        self.labelTitle.setGeometry(QtCore.QRect(280, 0, 291, 51))
        font = QtGui.QFont()
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.labelTitle.setFont(font)
        self.labelTitle.setObjectName("labelTitle")
        self.labelCh1 = QtWidgets.QLabel(self.centralwidget)
        self.labelCh1.setGeometry(QtCore.QRect(20, 90, 31, 51))
        self.labelCh1.setObjectName("labelCh1")
        self.labelCh2 = QtWidgets.QLabel(self.centralwidget)
        self.labelCh2.setGeometry(QtCore.QRect(20, 180, 31, 51))
        self.labelCh2.setObjectName("labelCh2")
        self.labelCh3 = QtWidgets.QLabel(self.centralwidget)
        self.labelCh3.setGeometry(QtCore.QRect(20, 260, 31, 51))
        self.labelCh3.setObjectName("labelCh3")
        self.widget = QtWidgets.QWidget(self.centralwidget)
        self.widget.setGeometry(QtCore.QRect(70, 70, 741, 261))
        self.widget.setObjectName("widget")
        self.gridLayout = QtWidgets.QGridLayout(self.widget)
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        self.gridLayout.setObjectName("gridLayout")
        self.ch1PlotWidget = PlotWidget(self.widget)
        self.ch1PlotWidget.setObjectName("ch1PlotWidget")
        self.gridLayout.addWidget(self.ch1PlotWidget, 0, 0, 1, 1)
        self.ch2PlotWidget = PlotWidget(self.widget)
        self.ch2PlotWidget.setObjectName("ch2PlotWidget")
        self.gridLayout.addWidget(self.ch2PlotWidget, 1, 0, 1, 1)
        self.ch3PlotWidget = PlotWidget(self.widget)
        self.ch3PlotWidget.setObjectName("ch3PlotWidget")
        self.gridLayout.addWidget(self.ch3PlotWidget, 2, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 845, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.labelTitle.setText(_translate("MainWindow", "EEG/ECG Recording GUI"))
        self.labelCh1.setText(_translate("MainWindow", "Ch 1"))
        self.labelCh2.setText(_translate("MainWindow", "Ch 2"))
        self.labelCh3.setText(_translate("MainWindow", "Ch 3"))
from pyqtgraph import PlotWidget


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

我的问题是如何整合这两者,以便在每个小部件中绘制实时图表? 理想情况下,我想使用超级 class,这样我就可以简单地导入未经编辑的 gui。

我尝试将 gui.Ui_MainWindow 导入 class,然后将 self.plt 覆盖为 self.Ch1PlotWidget

from pyqtgraph.Qt import QtGui, QtCore, QtWidgets
import gui as gui
import sys
import pyqtgraph as pg
import collections
import random
import time
import math
import numpy as np


class MainWindow(QtWidgets.QMainWindow, gui.Ui_MainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent=parent)
        self.setupUi(self)

        # Data stuff
        self.interval = 100
        self.bufsize = int(10 / self.interval)
        self.databuffer = collections.deque([0.0] * self.bufsize, self.bufsize)
        self.x = np.linspace(-10, 0.0, self.bufsize)
        self.y = np.zeros(self.bufsize, dtype=float)
        # PyQtGraph stuff
        self.app = QtGui.QApplication([])
        self.ch1PlotWidget = pg.plot(title='Live Plot')
        self.ch1PlotWidget.resize(600, 350)
        self.ch1PlotWidget.showGrid(x=True, y=True)
        # self.plt.setXRange(5,20, padding=0)
        self.ch1PlotWidget.setLabel('left', 'Amplitude', 'uVrms')
        self.ch1PlotWidget.setLabel('bottom', 'Time', 's')
        self.curve = self.ch1PlotWidget.plot(self.x, self.y, pen=(255, 0, 0))

        # QTimer
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.updateplot)
        self.timer.start(self.interval)

    def getdata(self):
        frequency = 0.5
        noise = random.normalvariate(0., 1.)
        new = 10. * math.sin(time.time() * frequency * 2 * math.pi) + noise
        return new

    def updateplot(self):
        self.databuffer.append(self.getdata())
        self.y[:] = self.databuffer
        self.curve.setData(self.x, self.y)
        self.app.processEvents()


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

抱歉所有代码,我只是对如何在 gui 中实现逻辑感到非常困惑。

这里有一个选项,您可以在其中使用两个 classes 并进行最小的更改。

更改 DynamicPlotter 构造函数以接受 PlotWidget 作为参数而不是创建一个新的,因为它们是在 Ui_Mainwindow 中创建并添加到布局中的。在 MainWindow class 中,为每个绘图创建一个 DynamicPlotter 对象(并保持持久引用,在这种情况下,我将它们添加到列表 self.plots)。

class DynamicPlotter:

    def __init__(self, plot, sampleinterval=0.1, timewindow=10., size=(600, 350)):
        # Data stuff
        self.interval = int(sampleinterval * 1000)
        self.bufsize = int(timewindow / sampleinterval)
        self.databuffer = collections.deque([0.0] * self.bufsize, self.bufsize)
        self.x = np.linspace(-timewindow, 0.0, self.bufsize)
        self.y = np.zeros(self.bufsize, dtype=float)
        
        # PyQtGraph stuff
        self.plt = plot
        self.plt.setTitle('EEG/ECG Live Plot')
        self.plt.resize(*size)
        self.plt.showGrid(x=True, y=True)
        #self.plt.setXRange(5,20, padding=0)
        self.plt.setLabel('left', 'Amplitude', 'uVrms')
        self.plt.setLabel('bottom', 'Time', 's')
        self.curve = self.plt.plot(self.x, self.y, pen=(255, 0, 0))

        # QTimer
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.updateplot)
        self.timer.start(self.interval)

    def getdata(self):
        frequency = 0.5
        noise = random.normalvariate(0., 1.)
        new = 10. * math.sin(time.time() * frequency * 2 * math.pi) + noise
        return new

    def updateplot(self):
        self.databuffer.append(self.getdata())
        self.y[:] = self.databuffer
        self.curve.setData(self.x, self.y)


class MainWindow(QtWidgets.QMainWindow, gui.Ui_MainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent=parent)
        self.setupUi(self)
        self.plots = []
        for plot in (self.ch1PlotWidget, self.ch2PlotWidget, self.ch3PlotWidget):
            self.plots.append(
                DynamicPlotter(plot, sampleinterval=0.05, timewindow=5.)
                )


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