使用pyqtgraph和线程进行实时绘图

问题描述 投票:1回答:1

这有点长,第一部分只是对问题的描述,第二部分是我的“修复”是否正确的问题。

我开始使用python编程。我创建了一个与Arduino通信的程序,该程序读取熔化实验室熔炉的温度。然后将温度用于PID算法,并将输出设置为Arduino。通过pyserial完成通信。到目前为止,everthing工作,包括温度信号的实时绘图,PID变量等。该脚本包括一个主循环和3个线程(串行通信,从serialport读取的datashifter,来自QWidget的设置温度和PID算法的输出。这个值用于创建一个数组,用于在pyqtgraph中显示。最后,第三个线程将数据从datashifter转移到QWidget。

使用我的Linux-Notebook时,一切正常,GUI永远不会停止更新。相反,当使用任何Windows主机时,我遇到一些pyqtgraphs停止刷新的问题。行为很奇怪,因为我使用相同的numpy数组(只是不同的列)或多或少地同时设置所有数据 - 一些图表刷新更长(小时),一些图表更早停止(几分钟)。在搜索或多或少的漏洞互联网;-)我认为我发现了问题:它是从一个线程传递到GUI的数据。一些虚拟代码来解释发生了什么:

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() 

调用self.gui.update()和processEvents()都不会对结果产生任何影响:图表会在一段时间后停止重绘(在Windows上)。

现在我有一个非常简单的例子,只是想确定我是否正确使用了线程。它工作正常,但我有一些问题:

  • 信号槽方法是否复制传递的数据?
  • 为什么没有必要调用QWidget的update()方法?
  • 使用信号时是否必须使用任何类型的锁?

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_())
python multithreading plot pyqt5 pyqtgraph
1个回答
5
投票

信号槽方法是否复制传递的数据?信号是线程安全的,当传输数据时,它们会复制,因此数据之前的线程和使用它的线程(GUI线程)不会产生冲突

为什么没有必要调用QWidget的update()方法?实际上pyqtgraph调用update方法,plot是一个PlotDataItem,所以如果我们检查setData()方法的源代码,它会调用updateItems()方法,在那个方法中调用curvescatter属性的setData()方法(根据类型)图形),在曲线的情况下,它的setData()方法调用updateData(),并且updateData()方法调用update,并且在散布的情况下,它的setData()方法调用addpoint(),并且addPoints()调用invalidate(),并且这个invalidate()方法调用update()。

使用信号时是否必须使用任何类型的锁?不,因为信号是线程安全的,所以Qt已经设置了防护装置以避免碰撞。

© www.soinside.com 2019 - 2024. All rights reserved.