首页 > 解决方案 > 使用 Figure() 对象更新 FigureCanvasQTAgg 画布

问题描述

我有一个 GUI,它有一个带有按钮的主窗口和一个带有默认图的 FigureCanvasQTAgg 画布(只是一些默认的散点)。按钮单击命令应使用 Figure() 对象作为参数更改画布。我想知道如何构造这样的函数来接收 Figure() 对象并更新画布。教程总是处理自行创建图形的更新函数,但在我的情况下,这样的更新函数应该接收图形(在 GUI 类之外计算)作为参数。下面你可以看到我的(可能是伪的)代码

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QRunnable, QThreadPool
from PyQt5.QtCore import *

import queue as Queue

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

import os, sys
import psutil

# Back up the reference to the exceptionhook
sys._excepthook = sys.excepthook

def my_exception_hook(exctype, value, traceback):
    # Print the error and traceback
    print(exctype, value, traceback)
    # Call the normal Exception hook after
    sys._excepthook(exctype, value, traceback)
    sys.exit(1)

# Set the exception hook to our wrapping function
sys.excepthook = my_exception_hook

def create_graph():

    ax = Figure().add_subplot ( 111 )
    ax.plot ( [1 , 2 , 3 , 4] , [10 , 20 , 25 , 30] , color = 'lightblue' , linewidth = 3 )

    return ax

class Worker(QRunnable):
    def __init__(self , queue):
        QRunnable.__init__ ( self )
        self.queue = queue

    @pyqtSlot()
    def run(self):

        ax = create_graph()
        self.queue.put ( ax )  ### transport ax object to GUI class

class Canvas ( FigureCanvas ):

    def __init__(self, parent, figure):

        self.fig = figure
        FigureCanvas.__init__ ( self , self.fig )
        self.setParent ( parent )

class GUI (QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1800, 900)
        MainWindow.move(40,20)

        self.centralwidget = QtWidgets.QWidget(MainWindow)

        self.fig , axes = plt.subplots ( 1 , 1 )
        plt.scatter ( [0 , 1 , 2 , 3 , 4 , 5] , [3 , 11 , 15 , 0 , 1 , 19] )
        self.canvas = Canvas(self, self.fig)

        self.canvas.setGeometry ( QtCore.QRect ( 30 , 400 , 811 , 381 ) )

        MainWindow.setCentralWidget(self.centralwidget)

        self.startButton = QtWidgets.QPushButton(self.centralwidget)
        self.startButton.setGeometry(QtCore.QRect(270, 310, 261, 51))
        self.startButton.clicked.connect(self.startCalc)
        self.startButton.setText('Press me to redraw graph')

    def startCalc(self):

            self.queue = Queue.Queue ()
            self.threadpool = QThreadPool ()
            print ( "Multithreading with maximum %d threads" % self.threadpool.maxThreadCount () )
            worker = Worker (self.queue)
            self.threadpool.start ( worker )

            QtCore.QTimer.singleShot ( 500 , self.process_queue )

    def process_queue(self):
        try:
            msg = self.queue.get ( 0 ) ### here we have our ax object

            self.fig.clear()

            # Here I dont know how to re-draw self.canvas widget with new data (ax)
            #Usualy one should create ax object right before canvas.draw function, but I have my ax object returned from outside the GUI class ... :((
            self.canvas.draw ()

        except Queue.Empty:
            # print('empty')
            QtCore.QTimer.singleShot ( 500 , self.process_queue )

def main():
    global window
    app = QtWidgets.QApplication ( sys.argv )  # Новый экземпляр QApplication
    window = GUI ()  # Создаём объект класса ExampleApp
    window.show ()  # Показываем окно
    try:
        sys.exit ( app.exec_ () )
    except:
        print ( "Exiting" )

if __name__ == '__main__':  # Если мы запускаем файл напрямую, а не импортируем
    main ()  # то запускаем функцию main()

标签: pythonmatplotlibpyqtpyqt5

解决方案


推荐阅读