3

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.

afp_2008
  • 1,940
  • 1
  • 19
  • 46

1 Answers1

2

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_()
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • What a neat solution! Thank you. Could you also comment on whether or not this approach would be appropriate for using timers instead of pressing keys for looping through slices of data? – afp_2008 Jun 16 '20 at 15:32
  • 1
    @AFP use QTimer – eyllanesc Jun 16 '20 at 15:36