web-dev-qa-db-ja.com

Qt DesignerフォームとPyQt5を使用してQWidget内にmatplotlibの図をプロットする

Matplotlibの図をQt Designerから作成されたフォームにリンクする最良の方法がわかりません。 QtDesignerで作成したフォームをコンパイルして、python pyuic5を使用してコンパイルします。メインプログラムは次のとおりです。

import app_framework as af
import matplotlib
from PyQt5 import QtWidgets
import sys

matplotlib.use('Qt5Agg')

app = QtWidgets.QApplication(sys.argv)
form = af.MyApp()
form.show()
app.exec_()

myAppは、Qt Designerから作成され、次にpyuic5(design.py)によって変換されたapp_framework.pyフォームを呼び出します。

from PyQt5.QtWidgets import QApplication, QMainWindow
import design

class MyApp(QMainWindow, design.Ui_mainWindow):
   def __init(self):
       super(self.__class__, self).__init__()
       <button initializations>
       <function definitions for button callbacks>

このフレームワークのどこでmatplotlibの図をQtDesignerの既成の空のウィジェット、またはそのようなものにリンクできるかについて混乱しているため、GUIウィンドウに新しいデータをプロットできます(入力されたテキスト、プッシュボタンなど)

ここで [〜#〜] so [〜#〜] および matplotlibのサイト でいくつかのスレッドを見つけましたが、作成するための正しいプロセスがわかりませんQt Designerフォーム内のこのウィジェット用のスペースは、プロットをリンクし、および/またはポストホックでウィジェットを作成し、リンクおよびプロットします。

これまでに行ったことは、Qt Creator内で空のQWidgetを作成し、pyuic5をコンパイルした後、design.pyファイルを次のように変更することです。

from PyQt5 import QtCore, QtGui, QtWidgets

# **** ADDED THIS
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as Canvas
# **** 

class Ui_mainWindow(object):
    def setupUi(self, mainWindow):
        <mainWindow setup stuff>
        self.centralwidget = QtWidgets.QWidget(mainWindow)

        # ****ALTERED THIS FROM self.plotWidget = QtWidgets.QWidget(self.centralWidget)
        self.plotWidget = MplWidget(self.centralWidget)
        # ***** 

        self.plotWidget.setGeometry(QtCore.QRect(20, 250, 821, 591))
        self.plotWidget.setObjectName("plotWidget")

  # **** ADDED THIS 
class MplCanvas(Canvas):
    def __init__(self):
        self.fig = Figure()
        self.ax = self.fig.add_subplot(111)
        Canvas.__init__(self, self.fig)
        Canvas.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
        Canvas.updateGeometry(self)


class MplWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)
        self.canvas = MplCanvas()
 # ***********

そしてapp_framework.pyとして:

from PyQt5.QtWidgets import QApplication, QMainWindow
import design

class MyApp(QMainWindow, design.Ui_mainWindow):
   def __init(self):
       super(self.__class__, self).__init__()
       self.setupUi(self)
       self.pushButton_plotData.clicked.connect(self.plot_data)

    def plot_data(self):
        x=range(0, 10)
        y=range(0, 20, 2)
        self.plotWidget.canvas.ax.plot(x, y)
        self.plotWidget.canvas.draw()

これはうまくいくと思いましたが、プロットのプッシュボタンをクリックしても何も起こりません。ロックアップせず、何もプロットしません。この空のウィジェットにmatplotlibの図やキャンバスをプロットするための基本的なものが欠けていると思います。

12

私はおそらくこの本にリンクしている SO post の助けを借りて解決策を見つけました 無料サンプルの章 おそらく購入する必要がある本です。他の多くの投稿で述べたように、ヘッダーmplwidgetを使用して、空のQtWidgetをMplWidgetに「昇格」する必要があります。これを実行してからpyuic5コマンドを実行すると、「from mplwidget import MplWidget」がdesign.pyファイルに表示されます。このファイルは、上書きを心配することなくいつでも更新できます。次に、次を使用してmplwidget.pyファイルを作成します。

# Imports
from PyQt5 import QtWidgets
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as Canvas
import matplotlib

# Ensure using PyQt5 backend
matplotlib.use('QT5Agg')

# Matplotlib canvas class to create figure
class MplCanvas(Canvas):
    def __init__(self):
        self.fig = Figure()
        self.ax = self.fig.add_subplot(111)
        Canvas.__init__(self, self.fig)
        Canvas.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
        Canvas.updateGeometry(self)

# Matplotlib widget
class MplWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)   # Inherit from QWidget
        self.canvas = MplCanvas()                  # Create canvas object
        self.vbl = QtWidgets.QVBoxLayout()         # Set box for plotting
        self.vbl.addWidget(self.canvas)
        self.setLayout(self.vbl)

そうすれば、アプリフレームワークは以前と同じようになります。実行し、プロットボタンを押すと、図が期待どおりに表示されます。私は基本的に、vblのものが欠落しているだけでQWidgetを手動で「プロモート」するためにすべてを行ったと思いますが、すべてはQt Designerフォームが編集されるたびに上書きされます。

app_framework.py:

from PyQt5.QtWidgets import QApplication, QMainWindow
import design

class MyApp(QMainWindow, design.Ui_mainWindow):
   def __init(self):
       super(self.__class__, self).__init__()
       self.setupUi(self)
       self.pushButton_plotData.clicked.connect(self.plot_data)

    def plot_data(self):
        x=range(0, 10)
        y=range(0, 20, 2)
        self.plotWidget.canvas.ax.plot(x, y)
        self.plotWidget.canvas.draw()

main.py:

from PyQt5 import QtWidgets
import sys

# Local Module Imports
import app_framework as af

# Create GUI application
app = QtWidgets.QApplication(sys.argv)
form = af.MyApp()
form.show()
app.exec_()
12