Multiple updating plot with pyqtgraph in Python

12,532

One problem is that you are appending to lists. This gets to be very slow when the lists grow large, as Python has to copy the full list to a new location that is one cell larger than the previous one. You could test this by running your code again with the appends removed, but continuing to read the data (which you throw away for that test).

If that is the problem, there are several solutions:

  1. preallocate a big list (say [None] * 1000) and keep a counter where you are writing. Wrap around when you reach 1k. This way, you get a continuous updating display like you see that on an old fashioned scope.
  2. Use numpy and preallocate a fixed buffer of say 1k samples. Add samples to the end (position -10 to -1). When you reach -1, move the buffer content 10 to the left in an efficient numpy data statement (something like buffer[0:-10] = buffer[10:], but there may be a dedicated numpy shift instruction) and start writing at -10 again.
Share:
12,532
cyberdyne
Author by

cyberdyne

Updated on June 11, 2022

Comments

  • cyberdyne
    cyberdyne about 2 years

    I have to plot 3 updating curves of data I read from a sensor. The updating plot is very fast when I use just a curve but when I try to plot them all each of them is drastically slower. The code I use is following:

    #!/usr/bin/python
    
    
    from pyqtgraph.Qt import QtGui, QtCore
    import pyqtgraph as pg
    
    import time
    import numpy as np
    
    
    app = QtGui.QApplication([])
    
    
    
    win = pg.GraphicsWindow()
    
    p1 = win.addPlot()
    p2 = win.addPlot()
    p3 = win.addPlot()
    
    
    curve1 = p1.plot()
    
    curve2 = p2.plot()
    
    curve3 = p3.plot()
    
    readData = [0.0, 0.0, 0.0]
    y1=[0.0]
    y2=[0.0]
    y3=[0.0]
    
    temp = [0.0]
    
    start = time.time()
    
    def update():
        global curve1, curve2, curve3
        t = time.time()-start         # measure of time as x-coordinate
        readData= readfun()        #function that reads data from the sensor it returns a list of 3 elements as the y-coordinates for the updating plots
        y1.append(readData[0])
        y2.append(readData[1])
        y3.append(readData[2])
        temp.append(t)
    
        curve1.setData(temp,y1)
        curve2.setData(temp,y2)
        curve3.setData(temp,y3)
        app.processEvents()
    
    
    
    timer = QtCore.QTimer()
    timer.timeout.connect(update)
    timer.start(0)
    
    
    
    
    if __name__ == '__main__':
        import sys
        if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_'):
            QtGui.QApplication.instance().exec_()
    

    How can I speed up the updating plotting for the three curves ? Thanks

    EDIT: Inspired by dirkjot's solution I want edit my above code in the case someone will need it for the same purpose. It works fine:

    #!/usr/bin/python
    
    
    from pyqtgraph.Qt import QtGui, QtCore
    import pyqtgraph as pg
    
    import time
    import numpy as np
    
    
    app = QtGui.QApplication([])
    
    win = pg.GraphicsWindow()
    
    p1 = win.addPlot()
    p2 = win.addPlot()
    p3 = win.addPlot()
    
    
    curve1 = p1.plot()
    
    curve2 = p2.plot()
    
    curve3 = p3.plot()
    
    readData = [0.0, 0.0, 0.0]
    y1=np.zeros(1000,dtype=float)
    y2=np.zeros(1000,dtype=float)
    y3=np.zeros(1000,dtype=float)
    
    indx = 0
    def update():
        global curve1, curve2, curve3, indx, y1,y2,y3
    
        readData= readfun()        #function that reads data from the sensor it returns a list of 3 elements as the y-coordinates for the updating plots
        y1[indx]=readData[0]
        y2[indx]=readData[1]
        y3[indx]=readData[2]
    
        if indx==99:
           y1=np.zeros(1000,dtype=float)
           y2=np.zeros(1000,dtype=float)
           y3=np.zeros(1000,dtype=float)
        else:
           indx+=1
        curve1.setData(y1)
        curve2.setData(y2)
        curve3.setData(y3)
        app.processEvents()
    
    
    
    timer = QtCore.QTimer()
    timer.timeout.connect(update)
    timer.start(0)
    
    
    
    
    if __name__ == '__main__':
        import sys
        if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_'):
            QtGui.QApplication.instance().exec_()