[英]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.