pyqtgraph 动态图:添加行以打开 GUI

pyqtgraph dynamic plot: add line to open GUI

我正在尝试向现有的打开的 Plot 添加新行。

我写了一个看门狗看一个有测量数据的文件夹。每隔几秒就会有一个新的数据文件。我尝试生成的应用程序应该在被看门狗触发时读取文件并将数据添加到绘图中。

更新现有数据时,使用 QTimer 和其他东西的动态图很容易,但我没有找到新行的钩子。

此外,当我想在 _exec() 上绘制脚本时 运行 是否必须使用多线程?

from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pq
import sys
import numpy as np
import time


class Plot2d(object):
    def __init__(self):
        self.traces = dict()
        self.num = 0
        pq.setConfigOptions(antialias=True)
        self.app = QtGui.QApplication(sys.argv)
        self.win = pq.GraphicsWindow(title='examples')
        self.win.resize(1000, 600)
        self.win.setWindowTitle('Windowtitle')
        self.canvas = self.win.addPlot(title='Plot')


    def starter(self):
        if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
            QtGui.QApplication.instance().exec_()

    def trace(self, name, dataset_x, dataset_y):
        if name in self.traces:
            self.traces[name].setData(dataset_x, dataset_y)
        else:
            self.traces[name] = self.canvas.plot(pen='y')

    def update(self, i):
        x_data = np.arange(0, 3.0, 0.01)
        y_data = x_data*i
        self.trace(str(i), x_data, y_data)
        self.trace(str(i), x_data, y_data)


if __name__ == '__main__':
    p = Plot2d()
    p.update(1)
    p.starter()
    time.sleep(1)
    p.update(2)

这是我试过的。当目录中有新数据可用时,看门狗应调用更新函数。

import time as time
from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler

if __name__ == "__main__":
    patterns = "*"
    ignore_patterns = ""
    ignore_directories = False
    case_sensitive = True
    go_recursively = False
    my_event_handler = PatternMatchingEventHandler(patterns, ignore_patterns, ignore_directories, case_sensitive)

    def on_created(event):
        print(f" {event.src_path} has been created!") #this function should call the plot update

    my_event_handler.on_created = on_created
    path = (r'C:\Users\...') #path from GUI at some point

    my_observer = Observer()
    my_observer.schedule(my_event_handler, path, recursive=go_recursively)
    my_observer.start()

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        my_observer.stop()
        my_observer.join()

exec_()方法是阻塞的,所以starter()也会阻塞,window关闭时会解锁,也就是说starter之后的所有代码只有关闭后才会执行window。另一方面,您不应在 GUI 线程中使用 time.sleep,因为它会阻止 GUI 事件循环的执行。

根据所使用的技术,提供了更新元素的方法,在 Qt 的情况下,适当的方法是使用信号,这样看门狗的所有逻辑都将封装在 QObject 中,该 QObject 将信息传输到GUI 通过信号,然后 GUI 获取该信息进行绘图。

import sys

from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler

from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pq
import numpy as np


class QObserver(QtCore.QObject):
    dataChanged = QtCore.pyqtSignal(object)

    def __init__(self, parent=None):
        super(QObserver, self).__init__(parent)
        patterns = "*"
        ignore_patterns = ""
        ignore_directories = False
        case_sensitive = True
        go_recursively = False

        path = r"C:\Users\..."  # path from GUI at some point

        event_handler = PatternMatchingEventHandler(
            patterns, ignore_patterns, ignore_directories, case_sensitive
        )
        event_handler.on_created = self.on_created
        self.observer = Observer()
        self.observer.schedule(event_handler, path, recursive=go_recursively)
        self.observer.start()

    def on_created(self, event):
        print(
            f" {event.src_path} has been created!"
        )  # this function should call the plot update
        self.dataChanged.emit(np.random.randint(1, 5))


class Plot2d(QtCore.QObject):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.traces = dict()
        self.num = 0
        pq.setConfigOptions(antialias=True)
        self.app = QtGui.QApplication(sys.argv)
        self.win = pq.GraphicsWindow(title="examples")
        self.win.resize(1000, 600)
        self.win.setWindowTitle("Windowtitle")
        self.canvas = self.win.addPlot(title="Plot")

    def starter(self):
        if (sys.flags.interactive != 1) or not hasattr(QtCore, "PYQT_VERSION"):
            QtGui.QApplication.instance().exec_()

    def trace(self, name, dataset_x, dataset_y):
        if name in self.traces:
            self.traces[name].setData(dataset_x, dataset_y)
        else:
            self.traces[name] = self.canvas.plot(pen="y")

    @QtCore.pyqtSlot(object)
    def update(self, i):
        x_data = np.arange(0, 3.0, 0.01)
        y_data = x_data * i
        self.trace(str(i), x_data, y_data)
        self.trace(str(i), x_data, y_data)


if __name__ == "__main__":
    p = Plot2d()
    qobserver = QObserver()
    qobserver.dataChanged.connect(p.update)
    p.starter()