【问题标题】:Matplotlib in Pyside with Qt designer (PySide)Pyside 中的 Matplotlib 与 Qt 设计器 (PySide)
【发布时间】:2016-07-27 15:17:09
【问题描述】:

我一直在寻找一个工作示例,如何在使用 QT 设计器创建的 pyside 中嵌入 matplotlib 图,同时将逻辑保存在单独的文件中。我知道网上有很多示例,但没有一个真正使用 QT 设计器,然后创建一个单独的文件来添加将 matplitlib 图添加到小部件的逻辑。我发现了一个“几乎”可以工作的示例http://blog.rcnelson.com/building-a-matplotlib-gui-with-qt-designer-part-1/,但在我的版本中,无法“将 layoutName 属性从“verticalLayout”更改为“mplvl”。

所以我有以下具体问题: 我不清楚该绘图可以嵌入到 Pyside Qt 设计器中的哪些项目。它是一个简单的“小部件”吗(因为 pyside 中没有可用的 matplotlib 小部件)。如果是这样,我该如何将绘图添加到该小部件?还是我必须用 Qt Designer 创建一个“FigureCanvas”?这可能吗?如果有,怎么做?

这是我可以使用 Pyside Qt 设计器在嵌入小部件时所做的最简单的设计(正确吗?)。我现在如何在它上面添加一个 matplotlib 图?

正如其中一个答案所建议的,我现在已将 Qwidget 提升为 MyStaticMplCanvas,并将 Qwidget 的名称编辑为 mplvl。

使用 Pyside Qt 设计器自动生成文件并编译 pyside-uic ui.ui -o ui.py -x

ui.py 看起来像这样:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'gui.ui'
#
# Created: Wed Apr 20 14:00:02 2016
#      by: pyside-uic 0.2.15 running on PySide 1.2.2
#
# WARNING! All changes made in this file will be lost!

from PySide import QtCore, QtGui

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(444, 530)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.mplvl = MyStaticMplCanvas(self.centralwidget)
        self.mplvl.setGeometry(QtCore.QRect(120, 190, 221, 161))
        self.mplvl.setObjectName("mplvl")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 444, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))

from mystaticmplcanvas import MyStaticMplCanvas

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

我现在如何从单独的 .py 文件中将绘图添加到 mplvl 对象中?

【问题讨论】:

  • 您不能在同一进程中混合使用 PyQtPySide 导入。我建议您从 matplotlib.backends.qt_compat 模块中导入所有内容,我们会在其中填充差异。
  • pyside的代码是由pyside-uic自动生成的,所以我需要保留。除非你说不可能?
  • 我也遇到了类似的问题——尽管有一些不同。请在 stackoverflow 上查看这篇文章:stackoverflow.com/questions/36665850/… 希望对您有所帮助。

标签: python matplotlib pyside


【解决方案1】:

我不是这方面的专家,所以这可能不是最干净的方法,但这里有一些工作代码可以帮助您入门:

  • 我认为添加小部件最简单的方法是通过QxxxxLayout
  • 然后我刚刚让你的Plotter继承自FigureCanvas
  • 并告诉matplotlibPySide 合作

ui.py:

from PySide import QtCore, QtGui

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(533, 497)
        self.mplvl = QtGui.QWidget(Form)
        self.mplvl.setGeometry(QtCore.QRect(150, 150, 251, 231))
        self.mplvl.setObjectName("mplvl")
        self.vLayout = QtGui.QVBoxLayout()
        self.mplvl.setLayout(self.vLayout)
        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))

为此,您只需将画布添加到QtDesigner 中的mplvl

main.py:

import matplotlib
matplotlib.use('Qt4Agg')
matplotlib.rcParams['backend.qt4'] = 'PySide'
from matplotlib.backends.backend_qt4agg import (
    FigureCanvasQTAgg as FigureCanvas,
    NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
from PySide import QtGui, QtCore
import random

from weakref import proxy
from ui import Ui_Form


class Plotter(FigureCanvas):
    def __init__(self, parent):
        ''' plot some random stuff '''
        self.parent = proxy(parent)
        # random data
        data = [random.random() for i in range(10)]
        fig = Figure()
        super(Plotter,self).__init__(fig)
        # create an axis
        self.axes = fig.add_subplot(111)
        # discards the old graph
        self.axes.hold(False)
        # plot data
        self.axes.plot(data, '*-')

    def binding_plotter_with_ui(self):
        self.parent.vLayout.insertWidget(1, self)

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    Form = QtGui.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    # plotter logic and binding needs to be added here
    plotter = Plotter(ui)
    plotter.binding_plotter_with_ui()
    plotter2 = Plotter(ui)
    plotter2.binding_plotter_with_ui()
    Form.show()
    sys.exit(app.exec_())

现在剩下的可能是调整FigureCanvas 以使其大小和比例正确,因此您应该能够在this examplethe other 中获得想要的结果。

祝你好运!

【讨论】:

  • 澄清:需要将小部件放入布局中。在这种情况下,wiedget 命名为 mplvl,垂直布局命名为 vLayout。之后上面的代码就可以工作了。
  • 唯一的小问题是情节在底部被切断了一点。有什么可以做的吗?
  • 我建议您执行以下操作:在 QtDesigner 中,添加第一个滚动区域,您可以在其中放置垂直布局(替换 mplvl)。然后在此布局内添加绘图。纵轴的尺寸问题,简单来说就是你的self.mplvl.setGeometry(QtCore.QRect(150, 150, 251, 231)),太小了。
【解决方案2】:

看看matplotlib在QT4中嵌入的例子:http://matplotlib.org/examples/user_interfaces/embedding_in_qt4.html

在这里,他们定义了几个在 QT4 应用程序中实现 matplotlib 小部件的类,例如班级MyStaticMplCanvas。在QT Designer中使用这个类的窍门是使用一个标准的QWidget,右键选择Promote to ...Promoted class name下填入类名MyStaticMplCanvas,在header file下找到这个类的文件名(扩展名 .h 被添加,但在 python 代码中被忽略)。点击AddPromote

现在通过 uic 编译后,python 代码应该类似于:

from PySide import QtCore, QtGui
class Ui_Form(object):
    def setupUi(self, Form):
        ...
        self.mplvl = MyStaticMplCanvas(Form)
        ...

from mystaticmplcanvas import MyStaticMplCanvas

【讨论】:

  • 这绝对是朝着正确方向迈出的一步。我现在唯一的问题是 self.setParent(parent) 给出了一个错误: TypeError: arguments did not match any overloaded call: QWidget.setParent(QWidget): argument 1 has unexpected type 'PySide.QtGui.QWidget' QWidget.setParent( QWidget,Qt.WindowFlags):参数 1 具有意外类型“PySide.QtGui.QWidget”
  • 确保只从 PySide 导入,而不从 PyQt4 导入。可能你的 matplotlib 默认使用 PyQt4。脚本的第一行在 matplotlib 中设置了正确的后端,如 Silmathoron 的回答。
  • 我现在已经编辑了原始问题以更好地显示事物的当前状态
猜你喜欢
  • 1970-01-01
  • 2011-10-07
  • 2013-07-21
  • 2014-12-29
  • 2017-06-07
  • 1970-01-01
  • 2020-05-02
  • 1970-01-01
  • 2014-10-28
相关资源
最近更新 更多