Redraw Matplotlib帆布而无需悬挂/冷冻GUI

发布于 2025-02-07 01:48:02 字数 3420 浏览 0 评论 0原文

我正在研究实时绘制数据的应用程序。

我已经使用pyqt5创建GUI和matplotlib来创建图形。

GUI由一个带有多个选项卡的窗口组成。 当前有4个选项卡,所有选项卡都有网格布局。 网格为2x3,包含图形的小部件是 在位置(0,0),(0,1),(0,2)和(1,0)。

我正在单独的线程中解析数据并处理数据。 然后将数据传递到包含图形的小部件 并清除图形,然后重新绘制。

我相信悬挂/冻结是由于 重新刷新的主线程中包含我的GUI。 这是我从阅读其他问题中收集的,但是 我还没有看到针对给定问题的工作解决方案。

有什么办法可以在绘图过程中完成 单独的线程使其不会悬挂/冻结GUI?

如果没有解决方案,是否还有另一个绘图库是线程安全的,并且可以很好地替代我要做的事情?

我在找到解决这个问题的示例方面没有任何成功, 或我完全理解的良好答案来解决它。

这是一篇相关的帖子,我不理解提供的答案,因为我不能 获取执行代码。
matplotlib和pyqt4: 下面绘制另一个

是我当前拥有的示例。

from PyQt5 import QtWidgets

from PyQt5.QtCore import (
    pyqtSignal, 
    QThread, 
    QObject, 
    )

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

import sys
import time
import random


class MainWindow(QtWidgets.QMainWindow):
    
    def __init__(self):
        super().__init__()

        self.tabWidget = QtWidgets.QTabWidget()
        self.setCentralWidget(self.tabWidget)
        
        self.tab1 = QtWidgets.QWidget()
        self.tab1_layout = QtWidgets.QGridLayout()
    
        GraphWidget_1 = GraphWidget()
        GraphWidget_2 = GraphWidget()
        GraphWidget_3 = GraphWidget()
        GraphWidget_4 = GraphWidget()
        
        self.tab1_layout.addWidget(GraphWidget_1, 0, 0)
        self.tab1_layout.addWidget(GraphWidget_2, 0, 1)
        self.tab1_layout.addWidget(GraphWidget_3, 1, 0)
        self.tab1_layout.addWidget(GraphWidget_4, 1, 1)
        
        self.tab1.setLayout(self.tab1_layout)
        self.tabWidget.addTab(self.tab1, "Tab1")
    
class GraphWidget(QtWidgets.QWidget):
    
    def __init__(self, parent = None):
        super().__init__()

        self.canvas = FigureCanvas(Figure())
        vertical_layout = QtWidgets.QVBoxLayout(self)
        vertical_layout.addWidget(self.canvas)

        self.fig = plt.figure(figsize = (4,4), dpi = 100)  
        self.fig.set_tight_layout(True)

        self.ax = self.fig.add_subplot(1, 1, 1)
        
        self.canvas.figure = self.fig
        
        self.worker_obj = Worker()
        self.thread = QThread()
        self.worker_obj.moveToThread(self.thread)
        self.worker_obj.update_graph_signal.connect(self.update_graph)
        self.thread.started.connect(self.worker_obj.perpetual_update)
        self.thread.start()
        
    def update_graph(self, x, y):
        print('update')
        self.ax.clear()
        self.ax.plot(x, y, color="orange")
        self.canvas.draw()

class Worker(QObject):
    
    update_graph_signal = pyqtSignal(list, list)
    
    def __init__(self):
        super().__init__()
        
    def perpetual_update(self):
        
        while True:
            time.sleep(5)
                    
            x = []
            y = []
            
            for i in range(0,3):
                n = random.randint(1,30)
                x.append(n)
                n = random.randint(1,30)
                y.append(n)
                            

            self.update_graph_signal.emit(x, y)

if __name__ == '__main__':
        
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.showMaximized()

    sys.exit(app.exec())

I am working on an application that plots data in real time.

I've used PyQt5 to create the GUI and Matplotlib to create the graphs.

The GUI consists of a window with multiple tabs.
There are currently 4 tabs and all of them have a grid layout.
The grid is 2x3, and the widgets that contain the graphs are
in locations (0,0), (0,1), (0,2), and (1, 0).

I am parsing the data, and processing it, in a separate thread.
The data is then passed to the widget that contains the graphs
and the graphs are cleared and then redrawn.

I believe that the hang/freeze is due to the
redrawing that is done within the main thread which contains my GUI.
This is what I've gathered from reading other questions, but
I have not seen a working solution to the given problem.

Is there any way that the drawing process can be done within a
separate thread so that it does not hang/freeze the GUI?

If there is no solution, is there another plotting library that is thread-safe and would be a good substitute for what I am trying to do?

I have not had any success in finding examples that solve this problem,
or good answers that I fully understand to address it.

Here is a related post in which I do not understand the provided answer as I cannot
get the code to execute.
matplotlib and pyqt4: update plot in one thread, draw in another

Below is an example of what I currently have.

from PyQt5 import QtWidgets

from PyQt5.QtCore import (
    pyqtSignal, 
    QThread, 
    QObject, 
    )

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

import sys
import time
import random


class MainWindow(QtWidgets.QMainWindow):
    
    def __init__(self):
        super().__init__()

        self.tabWidget = QtWidgets.QTabWidget()
        self.setCentralWidget(self.tabWidget)
        
        self.tab1 = QtWidgets.QWidget()
        self.tab1_layout = QtWidgets.QGridLayout()
    
        GraphWidget_1 = GraphWidget()
        GraphWidget_2 = GraphWidget()
        GraphWidget_3 = GraphWidget()
        GraphWidget_4 = GraphWidget()
        
        self.tab1_layout.addWidget(GraphWidget_1, 0, 0)
        self.tab1_layout.addWidget(GraphWidget_2, 0, 1)
        self.tab1_layout.addWidget(GraphWidget_3, 1, 0)
        self.tab1_layout.addWidget(GraphWidget_4, 1, 1)
        
        self.tab1.setLayout(self.tab1_layout)
        self.tabWidget.addTab(self.tab1, "Tab1")
    
class GraphWidget(QtWidgets.QWidget):
    
    def __init__(self, parent = None):
        super().__init__()

        self.canvas = FigureCanvas(Figure())
        vertical_layout = QtWidgets.QVBoxLayout(self)
        vertical_layout.addWidget(self.canvas)

        self.fig = plt.figure(figsize = (4,4), dpi = 100)  
        self.fig.set_tight_layout(True)

        self.ax = self.fig.add_subplot(1, 1, 1)
        
        self.canvas.figure = self.fig
        
        self.worker_obj = Worker()
        self.thread = QThread()
        self.worker_obj.moveToThread(self.thread)
        self.worker_obj.update_graph_signal.connect(self.update_graph)
        self.thread.started.connect(self.worker_obj.perpetual_update)
        self.thread.start()
        
    def update_graph(self, x, y):
        print('update')
        self.ax.clear()
        self.ax.plot(x, y, color="orange")
        self.canvas.draw()

class Worker(QObject):
    
    update_graph_signal = pyqtSignal(list, list)
    
    def __init__(self):
        super().__init__()
        
    def perpetual_update(self):
        
        while True:
            time.sleep(5)
                    
            x = []
            y = []
            
            for i in range(0,3):
                n = random.randint(1,30)
                x.append(n)
                n = random.randint(1,30)
                y.append(n)
                            

            self.update_graph_signal.emit(x, y)

if __name__ == '__main__':
        
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.showMaximized()

    sys.exit(app.exec())

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文