Search code examples
pythonpyqt5pyqtgraphqtguiqapplication

PyQtGraph: Issue looping through plotting slices of data


I have a python class that generates a numpy array of size 10000 and performs some calculation on it. The class has two plot methods and both use pyqtgraph

  • Plotting the entire data
  • Plotting segments of data one at a time (200 samples)

I was wondering how can I loop through the segments of data (200 samples at a time) and show the processed data to the user, and wait until the user presses any key before plotting the next 200 samples?

I would like to be able to update the plot without closing the Qt window to achieve a more efficient performance by just updating the content of the already plotted object.

import numpy as np
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph as pg

class testqt:

    def __init__(self):
        self.data = np.random.randn(10000) # for the sake of providing a MWE
        self.do_some_processing()

    def do_some_processing(self):
        self.data_processed = 2*self.data

    def plot_entire_processed_data(self):
        # Plot the entire processed data
        win = pg.GraphicsLayoutWidget(show=True)
        p = win.addPlot()
        curve_data = p.plot(self.data_processed)
        QtGui.QApplication.instance().exec_()

    def plot_processed_data_every_200(self):
        # animate the processed data in segments of 200 samples
        win = pg.GraphicsLayoutWidget(show=True)
        p = win.addPlot()
        curve_data = p.plot(self.data_processed[:200])

        for i in range(200, len(self.data_processed), 200):
            curve_data.setData(self.data_processed[i:i+200])
            # How can I pause here and use keyboard to move to the next 200 samples?
            # I would like to be able to visually evaluate each segment first and then 
            # press any key to see the next segment


        QtGui.QApplication.instance().exec_() # unfortunately, this only plot the last 200 samples


a = testqt()
a.plot_entire_processed_data()
a.plot_processed_data_every_200()

I would appreciate any help or hint.


Solution

  • To detect the keyboard event there are several options depending on the specific objective:

    • If you want to detect the pressing of any key when the focus is in the widget, then just override the keyPressEvent method of the window.

    • If you want to detect the pressing of any key even when the window does not have a key then you must use the OS libraries, in python fortunately there are wrappers such as pyinput, keyboard, etc.

    On the other hand, the logic is to obtain pieces of the data, so to do this, simply use a generator function.

    Considering the first case, the solution is:

    import numpy as np
    from pyqtgraph.Qt import QtCore, QtGui
    import pyqtgraph as pg
    
    
    def iter_by_step(data, step):
        for i in range(0, len(data), step):
            yield data[i : i + step]
    
    
    class GraphicsLayoutWidget(pg.GraphicsLayoutWidget):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            self.data = np.random.randn(10000)
            self.iter = None
    
            curve = self.addPlot()
            self.p = curve.plot()
    
        def do_some_processing(self):
            self.data_processed = 2 * self.data
            self.iter = iter_by_step(self.data_processed, 200)
            self.plot_processed_data_every_200()
    
        def keyPressEvent(self, event):
            super().keyPressEvent(event)
            if self.iter is not None:
                self.plot_processed_data_every_200()
    
        def plot_processed_data_every_200(self):
            try:
                data = next(self.iter)
            except StopIteration:
                pass
            else:
                self.p.setData(data)
    
    
    if __name__ == "__main__":
    
        w = GraphicsLayoutWidget()
        w.show()
        w.do_some_processing()
    
        QtGui.QApplication.instance().exec_()