PySide2 和 Matplotlib:如何在单独的进程中制作 MatPlotLib 运行? ..因为它不能在单独的线程中 运行
PySide2 and Matplotlib: How to make MatPlotLib run in a separate Process? ..as it cannot run in a separate Thread
我不是经验丰富的程序员,我正在尝试使用 Qt for python (PySide2) 在 python 中创建一种数据记录器程序来构建 GUI。我能够使用 Designer 创建一个图形用户界面并将其加载到 python 中。 gui 现在只是一个空白 window。然后我创建了一个函数,在 window 中显示一个图表,并使用 Qt 计时器在主程序的每个循环中更新数据。
一切正常,但 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_())
我不是经验丰富的程序员,我正在尝试使用 Qt for python (PySide2) 在 python 中创建一种数据记录器程序来构建 GUI。我能够使用 Designer 创建一个图形用户界面并将其加载到 python 中。 gui 现在只是一个空白 window。然后我创建了一个函数,在 window 中显示一个图表,并使用 Qt 计时器在主程序的每个循环中更新数据。
一切正常,但 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_())