簡體   English   中英

使用pyqtgraph和線程進行實時繪圖

[英]Real-Time-Plotting using pyqtgraph and threading

這有點長,第一部分只是問題的描述,第二部分是我的“修復”是否正確的問題。

我從python編程開始。 我創建了一個與Arduino通信的程序,該程序讀取了我們熔煉實驗室的熔爐溫度。 然后將溫度用於PID算法中,並將輸出設置為Arduino。 通信是通過pyserial完成的。 到目前為止,所有工作都可以進行,包括實時繪制溫度信號,PID變量等。 該腳本包括一個主循環和3個線程(串行通信,從串行端口讀取的數據移位器,QWidget的設定溫度和PID算法的輸出。此值用於創建一個數組,以在pyqtgraph中顯示。第三個線程將數據從datashifter移至QWidget。

使用我的Linux筆記本時,一切正常,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_())

信號插槽方法是否復制傳遞的數據? 信號是線程安全的,並且在傳輸數據時會進行復制,因此位於數據之前的線程和使用該線程的線程(GUI線程)不會發生沖突

為什么沒有必要調用QWidget的update()方法? 實際上pyqtgraph調用了update方法,plot是一個PlotDataItem,因此,如果我們檢查setData()方法的源代碼,它將調用updateItems()方法,在該方法中, 曲線散點屬性的setData()方法稱為(根據圖形的類型),在曲線的情況下,其setData()方法調用updateData(),而updateData()方法調用update,在散布的情況下,其setData()方法調用addpoint(),以及addPoints()調用invalidate(),而此invalidate()方法調用update()。

使用信號時是否必須使用任何類型的鎖? 不可以,因為信號是線程安全的,所以Qt已經設置了防護措施來避免沖突。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM