Wykreślanie rysunku matplotlib wewnątrz QWidget przy użyciu Qt Designer form i PyQt5

Nie rozumiem, jak połączyć rysunek matplotlib z formularzem stworzonym przez Qt Designer. Mam formularz, który stworzyłem w Qtdesignerze, a następnie skompilowałem do Pythona przez pyuic5. Mój główny program to:

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_()

Where myApp calls the app_framework.py formularz stworzony z Qt Designer następnie przekonwertowany przez pyuic5 (design.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>

Jestem zdezorientowany, gdzie w tym frameworku mogę połączyć figurę matplotlib z gotowym pustym widżetem w QtDesigner, czy coś z tego typu, dzięki czemu mogę wykreślić nowe dane w oknie GUI w miarę jak coś się dzieje(wprowadzony tekst, wciśnięcie przycisku itp.)

Znalazłem kilka wątków tutaj na więc i matplotlib ' s site , ale nie jestem pewien, czy Rozumiem poprawny proces tworzenia przestrzeni dla tego widgetu w postaci Qt Designer, a następnie łączenia wykresu, i / lub tworzenia widgetu post hoc, a następnie łączenia i kreślenia.

Do tej pory zrobiłem utworzenie pustego QWidget w Qt Creator, a następnie po pyuic5 kompiluje, zmieniam design.py plik w następujący sposób:

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()
 # ***********

I wtedy app_framework.py as:

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()

Myślałem, że to zadziała, ale kiedy kliknę przycisk wykresu, nic się nie dzieje. Nie zamyka się, po prostu nic nie knuje. Zgaduję, że brakuje mi czegoś fundamentalnego do kreślenia figury matplotlib i / lub płótna w tym pustym widżecie.

Author: Community, 2017-05-12

1 answers

Znalazłem rozwiązanie dzięki pomocy tego więc post, który łączy się z tym darmowy przykładowy Rozdział książki, którą prawdopodobnie będę musiał kupić. Jak wspomniano w wielu innych postach, trzeba "promować" pusty QtWidget do MplWidget za pomocą nagłówka mplwidget. Po wykonaniu tego, a następnie uruchomieniu polecenia pyuic5," from mplwidget import MplWidget " pojawi się w design.py plik, który można aktualizować w dowolnym momencie bez obawy o nadpisanie. Następnie utwórz na mplwidget.py Plik z:

# 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)

Następnie, app framework może być tak, jak miałem wcześniej. Po uruchomieniu i naciśnięciu przycisku wykresu postać pojawia się zgodnie z oczekiwaniami. Myślę, że w zasadzie zrobiłem wszystko, aby "promować" QWidget ręcznie, po prostu brakuje rzeczy vbl, ale wszystko, co byłoby nadpisywane za każdym razem, gdy formularz Qt Designer jest edytowany.

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_()
 21
Author: launchpadmcquack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:34