Multiple live plot GUI using pyqtgraph and PyQt5

Question:

I am trying to create a gui with several live plot EEG/ECG graphs (each plot on different axes).
From what I understand, I need to create multiple PlotWidgets inside a grid layout.

I have created a live plot using pyqtgraph, below however I am unsure how to merge this into the GUI:

from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import collections
import random
import time
import math
import numpy as 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()

Here is the basic GUI (3 plot widgets inside grid, and a few labels in mainWindow):

    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_())

My question is how do I integrate these two so I can plot the live graphs in each widget?
Ideally I want to use a super class so I can simply import the unedited gui.

I have tried importing the gui.Ui_MainWindow into the class and then overwriting the self.plt to 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_())

Sorry for all the code, I am just very confused on how to implement logic to the gui.

Asked By: Will Powell

||

Answers:

Here is an option where you can use both classes with minimal changes.

Change the DynamicPlotter constructor to accept a PlotWidget as a argument instead of creating a new one, since they are created and added to a layout in Ui_Mainwindow. In the MainWindow class, create a DynamicPlotter object for each plot (and keep a persistent reference, in this case I added them to a list 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_())

Answered By: alec
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.