2

i have some trouble to make a gui responsive while plotting live data. So that the GUI doesn't freeze, I try to thread all of my activities. I want to realize the following:

  1. Recording data through a serial port
  2. Calculations for the later plot in a thread
  3. Plotting in a thread (currently via a QTimer, but when i drag the window, there is always a "small" freeze and the plot does not update on the drag)

1 and 2 is done, but now im not sure how to update my plot in a seperate thread.

My PlotWidget get initiated looks like this:

self.plottingDQ = [queue.deque(maxlen=100), queue.deque(maxlen=100), queue.deque(maxlen=100)]
self.graph = pg.PlotWidget()
self.barItem = pg.BarGraphItem(x0=self.plottingDQ[0], y0=self.plottingDQ[1], width=self.plottingDQ[2], height=1)
self.graph.addItem(self.barItem)

starting my threads is done via a button which is connected to this function. Writer-Thread is not relevant because it has no dependency on the plot. But the Calculator-Thread calculates the data for updating the plot

def startPlotting(self):
    # not relevant for the example
    self.csvData = queue.Queue() 
    self.csv = Writer(self.csvData)
    self.csv.setDaemon(True)
    self.csv.start()

    self.calcData = queue.Queue()
    self.calcPlot = Calculator(self.calcData, self.plottingDQ)
    self.calcPlot.setDaemon(True)
    self.calcPlot.start()

    # Timer to update plot every x ms
    self.timer = QTimer()
    self.timer.timeout.connect(self.updatePlot)
    self.timer.start(500)

Right now im updating my plot within the Qtimer every 500ms

def updatePlot(self):
    print("update")
    self.barItem.setOpts()

So every time i get some input from my serial port i just pass the data to my thread and call something like this:

def fromPort(self, data):
    self.csvData.put(data)
    self.calcData.put(data)

Inside my Calculator-Thread the data will be calculated and handed over to the plottingDQ which is connected to the BarGraphItem

class Calculator(threading.Thread):
    def __init__(self, calcData, plottingDQ):
        threading.Thread.__init__(self)
        self.calcData = calcData
        self.plottingDQ = plottingDQ
        self.a = threading.Event()
        self.a.set()

    def run(self):
        while self.a.isSet():
            # Do some stuff here ...
            # After the calculations, i write the data into the plottingDQ
            
            self.plottingDQ[0].append(x)
            self.plottingDQ[1].append(y)
            self.plottingDQ[2].append(duration)

Is this the correct way to pass my calculated data from my Calcualtor-Thread into the deques which are used in the BarGraphItem? How can i update my BarGraphItem inside a thread?

enyo
  • 41
  • 4

2 Answers2

1

The way you programmed this looks fine. The root cause of the "stutter" seems to be an "update block" during the dragging process.

Try to enforce updates by adding pg.QtGui.QApplication.processEvents() to your updatePlot function, as described here:

def updatePlot(self):
    print("update")
    self.barItem.setOpts()
    pg.QtGui.QApplication.processEvents()
Christian Karcher
  • 2,533
  • 1
  • 12
  • 17
0

It may be better to use Qthread to deal with this, having a worker thread doing the plot update inside the app loop.

mrwonderfulness
  • 361
  • 2
  • 7