问题
this is a bit longer, the first part is just a description of the problem, the second one the question if my "fix" is correct.
I started with python programming. I created a program that communicates with an Arduino that reads the temperature of a furnace of our melting lab. The temperature is then used in a PID algorithm and an output is set to the Arduino. The communication is done via pyserial. So far, everthing works, including live plotting of the temperature signals, PID-variables and so on. The script includes a the main loop and 3 threads (serial communication, a datashifter that reads from serialport, the set temperature from the QWidget and the output of the PID algorithm. This values are used to create an array for displaying within pyqtgraph. Finally, the third thread shifts the data from the datashifter to the QWidget.
When using my Linux-Notebook, everything works fine, and the GUI never stops updating. In contrast, when using any Windows-Host, i have the problem that some pyqtgraphs stop to refresh. The behavior is strange, because i set all data at more or less the same time, with the same numpy array (just different columns) - some plots refresh longer (hours), some stop earlier (minutes). After searching more or less the hole internet ;-) I think that I found the problem: Its the passing of data from from a thread to the GUI. Some dummy code to explain what's going on:
DataUpdaterToGUI(QThread):
#sets the QWidget from main loop
def setGUI(self, gui):
self.gui = gui
def run()
while True:
with lock(): # RLock() Instance
copyArray = self.dataArray[:] # copy the array from the shifter
self.gui.plot1.copyArray(dataArray[:, 0], copyArray[:, 1])
self.gui.plot2.copyArray(dataArray[:, 0], copyArray[:, 2])
# self.gui.update()
# QApplication.instance().processEvents()
Neither calling self.gui.update() nor processEvents() has any influence on the outcome: The plots stop redrawing after a while (on windows).
Now i have a very simple example, and just want to make sure if I'm using the threading-stuff correctly. It works fine, but I have some questions:
- Does the signal-slot approach copy the passed data?
- Why is it not necessary to call the update() method of the QWidget?
- Do I have to use any kind of locks when using signals?
class Main(QWidget):
def __init__(self):
super().__init__()
self.layout = QGridLayout(self)
self.graph = pg.PlotWidget()
self.graph.setYRange(0,1000)
self.plot = self.graph.plot()
self.layout.addWidget(self.graph,0,0)
self.show()
def make_connection(self, data_object):
data_object.signal.connect(self.grab_data)
@pyqtSlot(object)
def grab_data(self, data):
print(data)
self.plot.setData(data)
class Worker(QThread):
signal = pyqtSignal(object)
def __init__(self):
super().__init__()
def run(self):
self.data = [0, 1]
i = 2
while True:
self.data[1] = i
self.signal.emit(self.data)
time.sleep(0.01)
i += 1
if __name__ == "__main__":
app = QApplication(sys.argv)
widget = Main()
worker = Worker()
widget.make_connection(worker)
worker.start()
sys.exit(app.exec_())
回答1:
Does the signal-slot approach copy the passed data? The signals are thread-safe and when transferring data they make a copy so the thread that precedes the data and the thread that consumes it (GUI Thread) will not have conflicts
Why is it not necessary to call the update() method of the QWidget? Actually pyqtgraph calls the update method, plot is a PlotDataItem, so if we check the source code of setData() method, it calls the updateItems() method, in that method the setData() method of the curve or scatter attribute is called (according to the type of graphics), in the case of curve its setData() method calls updateData(), and the updateData() method calls update, and in the case of the scatter its setData() method calls addpoint(), and addPoints() calls invalidate(), and this invalidate() method calls update().
Do I have to use any kind of locks when using signals? No, as the signals are thread-safe so Qt already has the guards set to avoid the collision.
来源:https://stackoverflow.com/questions/54961905/real-time-plotting-using-pyqtgraph-and-threading