Построение графиков в реальном времени с использованием pyqtgraph и потоков - PullRequest
0 голосов
/ 02 марта 2019

это немного длиннее, первая часть - просто описание проблемы, вторая - вопрос, правильно ли мое "исправление".

Я начал с программирования на Python.Я создал программу, которая связывается с Arduino, которая читает температуру печи нашей плавильной лаборатории.Затем температура используется в алгоритме PID, а выход устанавливается на Arduino.Связь осуществляется через pyserial.Пока что все работает, включая отображение температурных сигналов в реальном времени, ПИД-переменных и так далее.Сценарий включает в себя основной цикл и 3 потока (последовательное соединение, преобразователь данных, считывающий данные из последовательного порта, установленную температуру из QWidget и выходные данные алгоритма PID. Эти значения используются для создания массива для отображения в pyqtgraph. Наконец,третий поток переносит данные из преобразователя данных в QWidget.

При использовании моего Linux-ноутбука все работает нормально, и графический интерфейс никогда не перестает обновляться. Напротив, при использовании любого Windows-хоста у меня естьПроблема в том, что некоторые pyqtgraphs перестают обновляться. Поведение странное, потому что я установил все данные более или менее в одно и то же время, с одним и тем же массивом (только разные столбцы) - некоторые графики обновляются дольше (часы), некоторые останавливаются раньше (минутыПосле поиска более или менее дырки в интернете ;-) Я думаю, что нашел проблему: это передача данных из потока в 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 () не влияют на результат: графики через некоторое время перестают перерисовываться (в окнах).

Теперь у меня есть очень простой пример, и я просто хочу убедиться, правильно ли я использую потоки.Он работает нормально, но у меня есть несколько вопросов:

  • Подход с использованием сигнального слота копирует переданные данные?
  • Почему нет необходимости вызывать метод update () QWidget?
  • Нужно ли использовать какие-либо блокировки при использовании сигналов?

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 Ответ

0 голосов
/ 02 марта 2019

Копирует ли подход с использованием сигнального слота переданные данные? Сигналы являются поточно-ориентированными, и при передаче данных они копируют таким образом, что поток, предшествующий данным, и поток, который их использует (поток GUI)) не будет конфликтовать

Почему нет необходимости вызывать метод update () QWidget? На самом деле pyqtgraph вызывает метод обновления, plot представляет собой PlotDataItem, поэтому если мы проверяемИсходный код метода setData () вызывает метод updateItems () , в этом методе метод setData () кривой или scatterАтрибут вызывается (в соответствии с типом графики), в случае кривой его метод setData () вызывает updateData (), а метод updateData () вызывает updateи в случае разброса его setData () вызывает методы addpoint (), а addPoints () вызывает invalidate (), и это invalidate () вызовы метода update ().

Есть ли у меня хаиспользовать ли какие-либо блокировки при использовании сигналов? Нет, поскольку сигналы являются поточно-ориентированными, поэтому в Qt уже установлены защитные устройства, чтобы избежать столкновения.

...