0

I am working on a bigger project where i need to plot a lot of live data coming in. A very simplified version of my program is this (Kudos to https://stackoverflow.com/a/41687202/1482066):

from PyQt5 import QtCore, QtGui, QtWidgets
import pyqtgraph as pg
import random
import time

number_of_plots = 6
number_of_caps = 48
show_plots = True

print(f"Number of plots: {number_of_plots}")
print(f"Number of caps: {number_of_caps}")


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.central_widget = QtWidgets.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)
        self.data = dict()
        self.curve = dict()

        self.points_kwargs = list()

        colors = ["#000000", "#e6194B", "#f58231", "#3cb44b", "#42d4f4", "#4363d8", "#911eb4", "#f032e6", "#bfef45" ,"#000075", "#e6beff", "#9A6324"]

        self.colors = colors * 4

        for color in self.colors:
            self.points_kwargs.append({"pen": None,
                                       "symbol": 'x',
                                       "symbolSize": 8,
                                       "symbolPen": color,
                                       "symbolBrush": color})

    def plotter(self):
        for j in range(number_of_plots):
            self.data[j] = list()
            self.curve[j] = list()
            for i in range(number_of_caps):
                self.data[j].append([i])
                self.curve[j].append(self.login_widget.plots[j].getPlotItem().plot(**self.points_kwargs[i]))

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

    def updater(self):
        starttime = time.perf_counter()

        for key in self.data.keys():
            for i in range(number_of_caps):
                self.data[key][i].append(self.data[key][i][-1]+0.2*(0.5-random.random()))
                self.curve[key][i].setData(self.data[key][i])

        print(f"Plottime: {time.perf_counter() - starttime}")


class LoginWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(LoginWidget, self).__init__(parent)
        layout = QtWidgets.QHBoxLayout()
        self.button = QtWidgets.QPushButton('Start Plotting')
        layout.addWidget(self.button)

        self.plots = list()

        for i in range(number_of_plots):
            plot = pg.PlotWidget()
            self.plots.append(plot)
            layout.addWidget(plot)
            if not show_plots:
                plot.hide()

        self.plots[0].show()
        self.setLayout(layout)


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

The numbers on top show how this scales with plots and caps. 6 and 48 is why my program needs to handle. Running the program the plotting time is about 1sec/update. On my machine at least.

To make complicated matters easy: I would need to bring this plotting time down as much as possible. factor 2 might be okay, 10 would be very nice.

Any ideas? Thanks for your time!

Best

Kevin
  • 65
  • 6
  • Looking into it further, Rescaling the plot (which automatically happens when datapoints reach the end) seems to take about half the plotting time. Zooming out removes this and makes the plot twice as fast. I might be able to trick this into "bigger" chunks in my software but it doesn't really solve the problem – Kevin Feb 13 '20 at 17:03

1 Answers1

0

I figured out how to improve the speed in my case. As mentioned in my comment the plotting gets a lot faster if you zoom out. The rescaling of the plots actually takes the majority of the time required for the plotting. In my case plotting one point takes ~2-4ms and rescaling takes another 20-40ms.

I solved this issue by calculating the maximum x- and y-range my plot will have in the end and setting the range before plotting begins. This does not help if you don't know how much data will show up, but in this case the autoPan function might help. I added the following to my code:

plot.setXRange(min_x,max_x, 0.05)
plot.setYRange(min_y,max_y, 0.05)
plot.hideButtons()

.hideButtons() disables the autozoom button in the bottom left corner of the plot. This prevents the user from reenabling autozoom. The user can still zoom in and out if they like, but the automatic rescaling does no longer happen. This is not a perfect solution but works in my case.

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Kevin
  • 65
  • 6