【问题标题】:Inserting MatPlotLib graph into QWidget type将 MatPlotLib 图插入 QWidget 类型
【发布时间】:2019-07-25 02:30:42
【问题描述】:

我正在尝试将 MatPlotLib 图形插入到 QWidget 类型的小部件中,以便绘制来自传感器库的实时数据。这个想法是异步提取数据,将其转储到 numpy,然后使用 MatPlotLib 绘制它。

我的问题是 MatPlotLib 不想绘制成我构建的表格。我尝试将小部件分离到它自己的类中,但这也不起作用。所有在线教程似乎都是从一个空白表单开始,然后从代码构建它,而不是引用一个现成的 .ui 文件。

下面的代码被精简以简化事情:

from PyQt5 import uic, QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QAction

import matplotlib.pylab as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar

import numpy as np


class MyWindow(QMainWindow):

    def __init__(self):
        super(MyWindow, self).__init__()
        # importing ui that is made in Qt Designer
        uic.loadUi('MainForm.ui', self)

        # linking Exit option from File menu to exit action
        exitButton = QAction('Exit', self)
        exitButton.setShortcut('Ctrl+Q')
        exitButton.setStatusTip('Exit the program.')
        self.actionExit.triggered.connect(QApplication.quit)

        # add data
        data = np.array([0.7, 0.7, 0.7, 0.8, 0.9, 0.9, 1.5, 1.5, 1.5, 1.5])
        fig, ax1 = plt.subplots()
        bins = np.arange(0.6, 1.62, 0.02)
        n1, bins1, patches1 = ax1.hist(data, bins, alpha=0.6, density=False, cumulative=False)
        # plot
        self.plotWidget = FigureCanvas(plt.subplot)
        lay = QVBoxLayout(self.plotWidget)
        lay.setContentsMargins(0, 0, 0, 0)
        lay.addWidget(self.plotWidget)
        # add toolbar
        self.addToolBar(QtCore.Qt.BottomToolBarArea, NavigationToolbar(self.plotWidget, self))


if __name__ == "__main__":
    import sys

    app = QApplication(sys.argv)
    window = MyWindow()
    window.show()
    sys.exit(app.exec())

MainForm.ui 代码为:

<?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>800</width>
    <height>736</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <widget class="QWidget" name="plotWidgetHolder" native="true">
    <property name="geometry">
     <rect>
      <x>11</x>
      <y>11</y>
      <width>771</width>
      <height>484</height>
     </rect>
    </property>
    <property name="styleSheet">
     <string notr="true">background-color: rgb(255, 255, 255);</string>
    </property>
   </widget>
   <widget class="QPushButton" name="pushButton">
    <property name="geometry">
     <rect>
      <x>320</x>
      <y>570</y>
      <width>93</width>
      <height>28</height>
     </rect>
    </property>
    <property name="text">
     <string>PushButton</string>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>26</height>
    </rect>
   </property>
   <widget class="QMenu" name="menuFile">
    <property name="title">
     <string>File</string>
    </property>
    <addaction name="actionNew"/>
    <addaction name="actionOpen"/>
    <addaction name="separator"/>
    <addaction name="actionExit"/>
   </widget>
   <widget class="QMenu" name="menuData">
    <property name="title">
     <string>Data</string>
    </property>
    <addaction name="actionOpen_Data_Folder"/>
    <addaction name="actionOpen_in_Excel"/>
   </widget>
   <addaction name="menuFile"/>
   <addaction name="menuData"/>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
  <action name="actionNew">
   <property name="text">
    <string>New</string>
   </property>
  </action>
  <action name="actionOpen">
   <property name="text">
    <string>Open</string>
   </property>
  </action>
  <action name="actionOpen_in_Excel">
   <property name="text">
    <string>Open in Excel</string>
   </property>
  </action>
  <action name="actionOpen_Data_Folder">
   <property name="text">
    <string>Open Data Folder</string>
   </property>
  </action>
  <action name="actionExit">
   <property name="text">
    <string>Exit</string>
   </property>
  </action>
 </widget>
 <resources/>
 <connections/>
</ui>

使用此代码,我通常会收到错误代码“AttributeError: 'function' object has no attribute 'set_canvas'”,并且图形会在它自己的 MatPlotLib 生成窗口中弹出,而不是在较大的表单中。

任何帮助将不胜感激。

【问题讨论】:

  • self.plotWidget = FigureCanvas(fig)替换self.plotWidget = FigureCanvas(plt.subplot)
  • 另外,根本不要使用pylab或pyplot。删除该导入,这样您就不会想使用它。而是创建一个matplotlib.figure.Figure(),如您在该问题上找到的所有教程或示例中所示。

标签: python matplotlib pyqt pyqt5


【解决方案1】:

你需要更换

self.plotWidget = FigureCanvas(plt.subplot)
lay = QVBoxLayout(self.plotWidget)
lay.setContentsMargins(0, 0, 0, 0)
lay.addWidget(self.plotWidget)

self.plotWidget = FigureCanvas(fig)
self.setCentralWidget(self.plotWidget)

FigureCanvasQTAggconstructor 想要一个图形,而 QMainWidget 已经有了布局。

正如 ImportanceOfBeingErnest 正确所说,您还应该使用fig = matplotlib.figure.Figure() 构建您的图形。 (然后您可以使用ax1 = fig.gca() 获取您的坐标轴)

编辑: 要添加更多小部件,您必须将图形添加到需要父小部件的布局中:

self.plotWidget = FigureCanvas(fig)
self.someButton = QPushButton('click me')
container = QWidget()
layout = QGridLayout()
layout.addWidget(self.plotWidget,0,0)
layout.addWidget(self.someButton,1,0)
container.setLayout(layout)
self.setCentralWidget(container)

【讨论】:

  • 在这种情况下,说明fig 是什么非常重要。你看到我在问题下方的评论了吗?
  • 这个答案让我成功了 90%。该图形现在位于应用程序内部,但它占据了整个窗口,并且不允许查看或使用任何其他小部件。还有什么我想念的吗?我是否为 QWidget 类设置扩展属性?在某些时候,我需要主 UI 上的一些控制按钮。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2014-08-29
  • 2017-08-31
  • 2020-05-05
  • 2018-04-12
  • 1970-01-01
  • 2014-11-19
  • 2021-06-06
相关资源
最近更新 更多