簡體   English   中英

PySide2 和 Matplotlib:如何讓 MatPlotLib 在單獨的進程中運行? ..因為它不能在單獨的線程中運行

[英]PySide2 and Matplotlib: How to make MatPlotLib run in a separate Process? ..as it cannot run in a separate Thread

我不是經驗豐富的程序員,我正在嘗試在 python 中使用 ZE8801102A40AD89DDCFCFDCAEBF008D25Z 為 python (PySide2) 創建一種數據記錄器程序來構建 GUI。 我能夠使用 Designer 創建一個 gui,並將其加載到 python 中。 gui 現在只是一個空白的 window。 Then i created a function that launch MatplotLib in a window showing a graph, and i updtate data in each loop of the main program, using a Qt timer.

一切正常,但是 MatPlotLib 的重繪時間太慢了 gui 刷新。 所以我嘗試將 MatPlotLib 放在一個單獨的線程中,經過大量試驗,我明白它不能在單獨的線程中運行。最后我決定嘗試使用多處理。 現在 MatPlotLib 在單獨的進程中運行良好(我使用隊列將數據發送到 MatPlotLib)並在進程完成后正確退出,但是當我關閉主 window 時,程序更新完全關閉,同時鍵入 Ctrl+C 提示符是被封鎖。

這是我的代碼:

#!/usr/bin/env python3
import sys
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QApplication, QWidget
from PySide2.QtCore import QFile, QTimer

import matplotlib.pyplot as plt
from multiprocessing import Process, Queue, freeze_support
import random


class DSL(QWidget):
    def __init__(self):
        # LOAD HMI
        QWidget.__init__(self)
        designer_file = QFile('userInterface.ui')
        designer_file.open(QFile.ReadOnly)
        loader = QUiLoader()
        self.ui = loader.load(designer_file, self)
        designer_file.close()
        self.ui.show()

        # Data to be visualized
        self.data = []

    def mainLoop(self):
        self.data = []
        for i in range(10):
            self.data.append(random.randint(0, 10))

        # Send data to graph process
        queue.put(self.data)

        # LOOP repeater
        QTimer.singleShot(10, self.mainLoop)


def graphProcess(queue):
    for i in range(10):
        # Get data
        data = queue.get()

        # MatPlotLib
        plt.ion()
        plt.clf()
        plt.plot(data)
        plt.show()
        plt.pause(0.1)

    print('process end')


if __name__ == '__main__':
    # MatPlotLib Process
    queue = Queue()
    freeze_support()
    p = Process(target=graphProcess, args=(queue,))
    p.daemon = True
    p.start()

    # PySide2 Process
    app = QApplication(sys.argv)
    dsl = DSL()
    dsl.mainLoop()
    sys.exit(app.exec_())

與其在輔助進程中使用 matplotlib 不如在 QWidget 中嵌入 canvas 以使其在相同的 PySide2 進程中運行:

#!/usr/bin/env python3
import sys

from PySide2.QtCore import QFile, QObject, Signal, Slot, QTimer
from PySide2.QtWidgets import QApplication, QVBoxLayout, QWidget
from PySide2.QtUiTools import QUiLoader

import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure

import random


class DSL(QObject):
    dataChanged = Signal(list)

    def __init__(self, parent=None):
        # LOAD HMI
        super().__init__(parent)
        designer_file = QFile("userInterface.ui")
        if designer_file.open(QFile.ReadOnly):
            loader = QUiLoader()
            self.ui = loader.load(designer_file)
            designer_file.close()
            self.ui.show()
        # Data to be visualized
        self.data = []

    def mainLoop(self):
        self.data = []
        for i in range(10):
            self.data.append(random.randint(0, 10))
        # Send data to graph
        self.dataChanged.emit(self.data)
        # LOOP repeater
        QTimer.singleShot(10, self.mainLoop)


class MatplotlibWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        fig = Figure(figsize=(7, 5), dpi=65, facecolor=(1, 1, 1), edgecolor=(0, 0, 0))
        self.canvas = FigureCanvas(fig)
        self.toolbar = NavigationToolbar(self.canvas, self)
        lay = QVBoxLayout(self)
        lay.addWidget(self.toolbar)
        lay.addWidget(self.canvas)

        self.ax = fig.add_subplot(111)
        self.line, *_ = self.ax.plot([])

    @Slot(list)
    def update_plot(self, data):
        self.line.set_data(range(len(data)), data)

        self.ax.set_xlim(0, len(data))
        self.ax.set_ylim(min(data), max(data))
        self.canvas.draw()


if __name__ == "__main__":

    app = QApplication(sys.argv)
    dsl = DSL()
    dsl.mainLoop()

    matplotlib_widget = MatplotlibWidget()
    matplotlib_widget.show()

    dsl.dataChanged.connect(matplotlib_widget.update_plot)
    sys.exit(app.exec_())

暫無
暫無

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

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