在 pyqt5 小部件中更新 matplotlib

Posted

技术标签:

【中文标题】在 pyqt5 小部件中更新 matplotlib【英文标题】:Updating matplotlib in pyqt5 widget 【发布时间】:2021-02-18 20:49:53 【问题描述】:

我在 qt 设计器中创建了一个 UI 并使用 UIC 加载它。我对 UI 进行了更新,所以我不想将 UI 转换为 python。我正在使用以下帖子嵌入我的 PLT: Embed a matplotlib plot in a pyqt5 gui

但是,我尝试更新图表,但使用以下不同方法均失败:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>728</width>
    <height>429</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QWidget" name="graphWidget" native="true">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>10</y>
      <width>551</width>
      <height>351</height>
     </rect>
    </property>
    <property name="palette">
     <palette>
      <active>
       <colorrole role="WindowText">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>0</red>
          <green>0</green>
          <blue>0</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Button">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Light">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Midlight">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Dark">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>127</red>
          <green>127</green>
          <blue>127</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Mid">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>170</red>
          <green>170</green>
          <blue>170</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Text">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>0</red>
          <green>0</green>
          <blue>0</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="BrightText">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="ButtonText">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>0</red>
          <green>0</green>
          <blue>0</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Base">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Window">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Shadow">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>0</red>
          <green>0</green>
          <blue>0</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="AlternateBase">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="ToolTipBase">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>220</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="ToolTipText">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>0</red>
          <green>0</green>
          <blue>0</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="PlaceholderText">
        <brush brushstyle="SolidPattern">
         <color alpha="128">
          <red>0</red>
          <green>0</green>
          <blue>0</blue>
         </color>
        </brush>
       </colorrole>
      </active>
      <inactive>
       <colorrole role="WindowText">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>0</red>
          <green>0</green>
          <blue>0</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Button">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Light">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Midlight">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Dark">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>127</red>
          <green>127</green>
          <blue>127</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Mid">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>170</red>
          <green>170</green>
          <blue>170</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Text">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>0</red>
          <green>0</green>
          <blue>0</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="BrightText">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="ButtonText">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>0</red>
          <green>0</green>
          <blue>0</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Base">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Window">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Shadow">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>0</red>
          <green>0</green>
          <blue>0</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="AlternateBase">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="ToolTipBase">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>220</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="ToolTipText">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>0</red>
          <green>0</green>
          <blue>0</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="PlaceholderText">
        <brush brushstyle="SolidPattern">
         <color alpha="128">
          <red>0</red>
          <green>0</green>
          <blue>0</blue>
         </color>
        </brush>
       </colorrole>
      </inactive>
      <disabled>
       <colorrole role="WindowText">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>127</red>
          <green>127</green>
          <blue>127</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Button">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Light">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Midlight">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Dark">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>127</red>
          <green>127</green>
          <blue>127</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Mid">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>170</red>
          <green>170</green>
          <blue>170</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Text">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>127</red>
          <green>127</green>
          <blue>127</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="BrightText">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="ButtonText">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>127</red>
          <green>127</green>
          <blue>127</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Base">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Window">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="Shadow">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>0</red>
          <green>0</green>
          <blue>0</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="AlternateBase">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>255</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="ToolTipBase">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>255</red>
          <green>255</green>
          <blue>220</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="ToolTipText">
        <brush brushstyle="SolidPattern">
         <color alpha="255">
          <red>0</red>
          <green>0</green>
          <blue>0</blue>
         </color>
        </brush>
       </colorrole>
       <colorrole role="PlaceholderText">
        <brush brushstyle="SolidPattern">
         <color alpha="128">
          <red>0</red>
          <green>0</green>
          <blue>0</blue>
         </color>
        </brush>
       </colorrole>
      </disabled>
     </palette>
    </property>
    <property name="autoFillBackground">
     <bool>true</bool>
    </property>
   </widget>
   <widget class="QPushButton" name="start">
    <property name="geometry">
     <rect>
      <x>590</x>
      <y>30</y>
      <width>91</width>
      <height>41</height>
     </rect>
    </property>
    <property name="text">
     <string>Start</string>
    </property>
   </widget>
   <widget class="QPushButton" name="restart">
    <property name="enabled">
     <bool>false</bool>
    </property>
    <property name="geometry">
     <rect>
      <x>590</x>
      <y>100</y>
      <width>91</width>
      <height>41</height>
     </rect>
    </property>
    <property name="text">
     <string>Restart</string>
    </property>
    <property name="checkable">
     <bool>true</bool>
    </property>
   </widget>
   <widget class="QLabel" name="label_7">
    <property name="geometry">
     <rect>
      <x>730</x>
      <y>130</y>
      <width>171</width>
      <height>71</height>
     </rect>
    </property>
    <property name="text">
     <string/>
    </property>
    <property name="alignment">
     <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
    </property>
    <property name="wordWrap">
     <bool>true</bool>
    </property>
   </widget>
   <widget class="QPushButton" name="intervene">
    <property name="enabled">
     <bool>true</bool>
    </property>
    <property name="geometry">
     <rect>
      <x>590</x>
      <y>170</y>
      <width>91</width>
      <height>41</height>
     </rect>
    </property>
    <property name="text">
     <string>Intervene</string>
    </property>
    <property name="checkable">
     <bool>false</bool>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>728</width>
     <height>21</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>


from PyQt5 import QtCore, QtWidgets, uic
import pyqtgraph as pg
import sys  # We need sys so that we can pass argv to QApplication
import time
import matplotlib
import matplotlib.pylab as plt
from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
import numpy as np
from scipy.spatial import Voronoi, voronoi_plot_2d

matplotlib.use('QT5Agg')


class MainWindow(QtWidgets.QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        # Load the UI
        uic.loadUi('src\Main.ui', self)

        # Runs functions on button press
        self.start.clicked.connect(self.startfcn)

        # add toolbar
        # self.addToolBar(QtCore.Qt.BottomToolBarArea, NavigationToolbar(self.canvas, self))
    # This function is run when the start button is pushed
    def startfcn(self):
        sd = 20
        # rng(sd)
        numIterations = 1000
        samplingPeriod = 10
        xrange = 10  # region size
        yrange = 5
        n = 20  # number of robots (changing the number of robots is interesting)
        dt = 1
        maxSpeed = 8

        # Draw graph
        points = np.random.rand(10, 2)  # random points for Voronoi
        vor = Voronoi(points)  # Create Voronoi object
        fig = voronoi_plot_2d(vor)  # Make vor object into a plot object
        canvas = FigureCanvas(fig)  # create a mpl canvas obj
        lay = QtWidgets.QVBoxLayout(self.graphWidget)  # create layout in graph widget
        lay.setContentsMargins(0, 0, 0, 0)
        lay.addWidget(canvas)  # add canvas obj to layout
        # all of these are attempts to update the graph
        canvas.draw()
        self.graphWidget.update()
        self.graphWidget.show()
        QtWidgets.QApplication.processEvents()


def main():
    app = QtWidgets.QApplication(sys.argv)
    main = MainWindow()
    main.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

当按下开始按钮时,它应该显示一个新的随机 voronoi 图,但它没有。

每次按下开始按钮时我都需要它来更新 graphWidget。

【问题讨论】:

我不知道为什么 UI 这么长,但它基本上是主窗口和一个名为 graphWidget 的 qwidget,然后是一些按钮 再次按下按钮应该会显示一个新的随机 voronoi 图,这不起作用 【参考方案1】:

如果您要更改 Figure,那么您必须创建一个新的画布,这样您就必须销毁之前的画布:

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.canvas = None

        uic.loadUi("Main.ui", self)
        self.canvas_layout = QtWidgets.QVBoxLayout(self.graphWidget)
        self.canvas_layout.setContentsMargins(0, 0, 0, 0)

        self.start.clicked.connect(self.startfcn)

        # add toolbar
        # self.addToolBar(QtCore.Qt.BottomToolBarArea, NavigationToolbar(self.canvas, self))

    # This function is run when the start button is pushed
    def startfcn(self):
        # Draw graph
        points = np.random.rand(10, 2)  # random points for Voronoi
        vor = Voronoi(points)  # Create Voronoi object
        fig = voronoi_plot_2d(vor)  # Make vor object into a plot object

        if self.canvas is not None:
            self.canvas.deleteLater()

        self.canvas = FigureCanvas(fig)

        self.canvas_layout.addWidget(self.canvas)

另一个更好的选择是通过“ax”参数将坐标轴传递给voronoi_plot_2d()方法:

import sys

from PyQt5 import QtCore, QtWidgets, uic

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

import numpy as np

from scipy.spatial import Voronoi, voronoi_plot_2d

matplotlib.use("QT5Agg")


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.canvas = FigureCanvas(Figure())

        uic.loadUi("Main.ui", self)
        lay = QtWidgets.QVBoxLayout(self.graphWidget)
        lay.setContentsMargins(0, 0, 0, 0)
        lay.addWidget(self.canvas)

        self.start.clicked.connect(self.startfcn)

        self.ax = None

        # add toolbar
        # self.addToolBar(QtCore.Qt.BottomToolBarArea, NavigationToolbar(self.canvas, self))

    # This function is run when the start button is pushed
    def startfcn(self):
        if self.ax is None:
            self.ax = self.canvas.figure.subplots()
        # Draw graph
        points = np.random.rand(10, 2)  # random points for Voronoi
        vor = Voronoi(points)  # Create Voronoi object
        self.ax.clear()
        voronoi_plot_2d(vor, ax=self.ax)  # Make vor object into a plot object
        self.canvas.draw()


def main():
    app = QtWidgets.QApplication(sys.argv)
    main = MainWindow()
    main.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

【讨论】:

第一种方法会给你一个警告,警告你打开了太多的地块。我实现了类似第二个的东西。此外,我能找到的唯一有用的 MPL 文档:matplotlib.org/3.1.1/gallery/user_interfaces/… @bobthebuilder 什么工具给你这个警告? 使用pycharm,终端输出警告

以上是关于在 pyqt5 小部件中更新 matplotlib的主要内容,如果未能解决你的问题,请参考以下文章

Matplotlib 和 PyQt5 绘图图

从 Matplotlib 图中提取信息并将其显示在 PyQt5 GUI 中

尽管更新了小部件,但 Pyqt5 更新的小部件未添加到布局中

MatPlotLib PyQt5 布局问题

Matplotlib 将图形嵌入到 UI PyQt5

在 PyQt5 中,右小部件比其他小部件短