Live Plotting with PyQtGraph in PyQt4

Ivy picture Ivy · Jan 16, 2017 · Viewed 7.7k times · Source

I am quite new in Python and TRYING to make a PyQt4 app, where I am embedding PyQtGraph in it. I've got this PyQtGraph live plotter that works fantastically:

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

app = QtGui.QApplication([])
p = pg.plot()
curve = p.plot()
data = [0]

def updater():

    data.append(random.random())
    curve.setData(data) #xdata is not necessary


timer = QtCore.QTimer()
timer.timeout.connect(updater)
timer.start(0)

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

For embedding in a bigger PyQt4 app, I need a layout for including a pyqtgraph.PlotWidget(). For that matter I set a centralWidget in my MainWindow. I create a button, that should start plotting just as the previous code does, but just nothing happens when I call the updater function through the plotter function:

import sys
from PyQt4 import QtCore, QtGui
import pyqtgraph as pg
import random

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.central_widget = QtGui.QStackedWidget()
        self.setCentralWidget(self.central_widget)
        login_widget = LoginWidget(self)#to say where the button is
        login_widget.button.clicked.connect(self.plotter)
        self.central_widget.addWidget(login_widget)

    def plotter(self):
        self.data =[0]
        timer = QtCore.QTimer()
        timer.timeout.connect(self.updater)
        timer.start(0)

    def updater(self):

        self.data.append(random.random())
        plot.setData(self.data)

class LoginWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        global plot
        super(LoginWidget, self).__init__(parent)
        layout = QtGui.QHBoxLayout()
        self.button = QtGui.QPushButton('Start Plotting')
        layout.addWidget(self.button)
        plot = pg.PlotWidget()
        layout.addWidget(plot)
        self.setLayout(layout)

if __name__ == '__main__':
    app = QtGui.QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()

Is nothing happening because I have to thread?

Answer

ImportanceOfBeingErnest picture ImportanceOfBeingErnest · Jan 17, 2017

There are several things to consider in the code.
First, going in the same direction as @luddek's answer, you need to keep track of your variables. If you define a variable inside a class method and this class method finished executing, the variable is lost. Also it is not visible from the outside.
It is therefore a good idea to use instance variables,
self.plot instead of plot
self.timer instead of timer
self.login_widget instead of login_widget
(also, I would not recomment using global in a PyQt programm, although it is valid code)

Next, PlotWidget does not have a setData method. Plotting the data to the PlotItem's plot is a little more involved:
pg.PlotWidget() has a PlotItem which you can get via .getPlotItem(). Then you need to invoke plot() on it, which returns the actual curve you want to add data to. In the example below I introduced the new variable self.curve to which you can add the data via self.curve.setData(self.data)

Here is the complete working code.

from PyQt4 import QtCore, QtGui
import pyqtgraph as pg
import random

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.central_widget = QtGui.QStackedWidget()
        self.setCentralWidget(self.central_widget)
        self.login_widget = LoginWidget(self)
        self.login_widget.button.clicked.connect(self.plotter)
        self.central_widget.addWidget(self.login_widget)

    def plotter(self):
        self.data =[0]
        self.curve = self.login_widget.plot.getPlotItem().plot()

        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.updater)
        self.timer.start(0)

    def updater(self):

        self.data.append(self.data[-1]+0.2*(0.5-random.random()) )
        self.curve.setData(self.data)

class LoginWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        super(LoginWidget, self).__init__(parent)
        layout = QtGui.QHBoxLayout()
        self.button = QtGui.QPushButton('Start Plotting')
        layout.addWidget(self.button)
        self.plot = pg.PlotWidget()
        layout.addWidget(self.plot)
        self.setLayout(layout)

if __name__ == '__main__':
    app = QtGui.QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()