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

Posted

技术标签:

【中文标题】pyqtgraph 动态绘图:添加行以打开 GUI【英文标题】:pyqtgraph dynamic plot: add line to open GUI 【发布时间】:2020-06-09 00:11:21 【问题描述】:

我正在尝试将新行添加到现有和打开的绘图中。

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

在更新现有数据时,使用 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()

【问题讨论】:

显示看门狗代码 【参考方案1】:

exec_() 方法是阻塞的,所以 starter() 也是阻塞的,并且会在关闭窗口时解锁,这意味着 starter 之后的所有代码只有在关闭窗口后才会执行。另一方面,您不应该在 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()

【讨论】:

感谢您的快速答复。我想我到目前为止都明白了。但对我来说还有很多东西要学。

以上是关于pyqtgraph 动态绘图:添加行以打开 GUI的主要内容,如果未能解决你的问题,请参考以下文章

在线程内更新 pyqtgraph BarGraphItem

pyqtgraph绘图案例-动态的正余弦波形图

pyqtgraph:为绘图中的线条添加图例

pyqtgraph绘图如何使用pyqtgraph

Pyqtgraph 绘图很慢

防止创建绘图窗口 - Pyqtgraph plot