Wie man matplotlib in pyqt einbettet - für Dummies

77

Ich versuche derzeit, ein Diagramm, das ich zeichnen möchte, in eine von mir entworfene pyqt4-Benutzeroberfläche einzubetten. Da ich fast völlig neu in der Programmierung bin - ich verstehe nicht, wie die Leute die Einbettung in die Beispiele gemacht haben, die ich gefunden habe - dieses (unten) und dieses .

Es wäre fantastisch, wenn jemand eine schrittweise Erklärung oder zumindest einen sehr kleinen, sehr einfachen Code veröffentlichen könnte, der nur z. B. ein Diagramm und eine Schaltfläche in einer pyqt4-GUI erstellt.

ari
quelle

Antworten:

113

Es ist eigentlich nicht so kompliziert. Relevante Qt-Widgets sind in matplotlib.backends.backend_qt4agg. FigureCanvasQTAggund NavigationToolbar2QTsind in der Regel das, was Sie brauchen. Dies sind reguläre Qt-Widgets. Sie behandeln sie wie jedes andere Widget. Unten ist ein sehr einfaches Beispiel mit einem Figure, Navigationund eine einzelne Taste , die einige Zufallsdaten zieht. Ich habe Kommentare hinzugefügt, um die Dinge zu erklären.

import sys
from PyQt4 import QtGui

from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure

import random

class Window(QtGui.QDialog):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        # a figure instance to plot on
        self.figure = Figure()

        # this is the Canvas Widget that displays the `figure`
        # it takes the `figure` instance as a parameter to __init__
        self.canvas = FigureCanvas(self.figure)

        # this is the Navigation widget
        # it takes the Canvas widget and a parent
        self.toolbar = NavigationToolbar(self.canvas, self)

        # Just some button connected to `plot` method
        self.button = QtGui.QPushButton('Plot')
        self.button.clicked.connect(self.plot)

        # set the layout
        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.toolbar)
        layout.addWidget(self.canvas)
        layout.addWidget(self.button)
        self.setLayout(layout)

    def plot(self):
        ''' plot some random stuff '''
        # random data
        data = [random.random() for i in range(10)]

        # create an axis
        ax = self.figure.add_subplot(111)

        # discards the old graph
        ax.clear()

        # plot data
        ax.plot(data, '*-')

        # refresh canvas
        self.canvas.draw()

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)

    main = Window()
    main.show()

    sys.exit(app.exec_())

Bearbeiten :

Aktualisiert, um Kommentare und API-Änderungen widerzuspiegeln.

  • NavigationToolbar2QTAgg geändert mit NavigationToolbar2QT
  • Direkt importieren Figurestattpyplot
  • Ersetzen Sie veraltet ax.hold(False)durchax.clear()
Avaris
quelle
14
Beachten Sie, dass gemäß dieser SO-Anmerkung beim Einbetten kein Pyplot importiert werden sollte. Es macht funky Dinge wie das Ausführen einer eigenen GUI mit einer eigenen Hauptschleife. Es gibt ein Matplotlib-Beispiel zum Einbetten
Laurence Billingham
9
Ich habe einen Fehler: MatplotlibDeprecationWarning: Diese Klasse ist in 1.4 veraltet, da sie keine zusätzlichen Funktionen enthält NavigationToolbar2QT. Bitte ändern Sie Ihren Code, um NavigationToolbar2QTstattdessen mplDeprecation zu verwenden)
GSandro_Strongs
5
@ gs_developer_user3605534 Ersetzen NavigationToolbar2QTAggdurch Beenden NavigationToolbar2QTder Nachricht
SAAD
Wenn ich diesen Code verwende, werden zwei Fenster erstellt, ein Qt-Hauptfenster und eine Matplotlib-Figur. Wie kann ich das vermeiden, sodass nur ein Qt-Hauptfenster erstellt wird? Ich verwende Python 3.4 32bit, matplotlib 1.5.3 und PyQt4 (ich auch ändern musste NavigationToolbar2QTAggzu NavigationToolbar2QT). Ich fand, dass eine Lösung IPython
C Winkler
Ich benutze dies, um ein QVBoxLayoutin ein Hauptfenster zu setzen. Gibt es eine Möglichkeit, die Leinwand und die Figur dazu zu bringen, ein hohes Rechteck zu füllen (ungefähr 1,5-mal so hoch wie breit)?
Kajsa
73

Unten finden Sie eine Anpassung des vorherigen Codes für die Verwendung unter PyQt5 und Matplotlib 2.0 . Es gibt eine Reihe kleiner Änderungen: Struktur der PyQt-Submodule, andere Submodule von Matplotlib, veraltete Methode wurde ersetzt ...


import sys
from PyQt5.QtWidgets import QDialog, QApplication, QPushButton, QVBoxLayout

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

import random

class Window(QDialog):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        # a figure instance to plot on
        self.figure = plt.figure()

        # this is the Canvas Widget that displays the `figure`
        # it takes the `figure` instance as a parameter to __init__
        self.canvas = FigureCanvas(self.figure)

        # this is the Navigation widget
        # it takes the Canvas widget and a parent
        self.toolbar = NavigationToolbar(self.canvas, self)

        # Just some button connected to `plot` method
        self.button = QPushButton('Plot')
        self.button.clicked.connect(self.plot)

        # set the layout
        layout = QVBoxLayout()
        layout.addWidget(self.toolbar)
        layout.addWidget(self.canvas)
        layout.addWidget(self.button)
        self.setLayout(layout)

    def plot(self):
        ''' plot some random stuff '''
        # random data
        data = [random.random() for i in range(10)]

        # instead of ax.hold(False)
        self.figure.clear()

        # create an axis
        ax = self.figure.add_subplot(111)

        # discards the old graph
        # ax.hold(False) # deprecated, see above

        # plot data
        ax.plot(data, '*-')

        # refresh canvas
        self.canvas.draw()

if __name__ == '__main__':
    app = QApplication(sys.argv)

    main = Window()
    main.show()

    sys.exit(app.exec_())
Anabar
quelle
Sehr nützliches Update, läuft gut! Könnten Sie eine Referenz für ax.holddie Veralterung angeben? Warum nicht auch ax.cleardie Axes-Instanz wiederverwenden?
Pierre H.
3
Ich denke, es ist nicht matplotlib.pyplotempfehlenswert, beim Einbetten von matplotlib in pyqt zu importieren (bitte korrigieren Sie mich, wenn ich in dieser Situation falsch liege). Wenn ich richtig bin, habe ich meine Matplotlib mit dieser Methode in diesen SO-Beitrag eingebettet, der kein Pyplot importiert: stackoverflow.com/questions/43947318/…
hhprogram
Wie zeichne ich Bilder auf der Leinwand?
Neeraj Kumar
2

Für diejenigen, die nach einer dynamischen Lösung suchen, um Matplotlib in PyQt5 einzubetten (sogar Daten per Drag & Drop zeichnen). In PyQt5 müssen Sie Super für die Hauptfensterklasse verwenden, um die Drops zu akzeptieren. Die dropevent-Funktion kann verwendet werden, um den Dateinamen abzurufen, und der Rest ist einfach:

def dropEvent(self,e):
        """
        This function will enable the drop file directly on to the 
        main window. The file location will be stored in the self.filename
        """
        if e.mimeData().hasUrls:
            e.setDropAction(QtCore.Qt.CopyAction)
            e.accept()
            for url in e.mimeData().urls():
                if op_sys == 'Darwin':
                    fname = str(NSURL.URLWithString_(str(url.toString())).filePathURL().path())
                else:
                    fname = str(url.toLocalFile())
            self.filename = fname
            print("GOT ADDRESS:",self.filename)
            self.readData()
        else:
            e.ignore() # just like above functions  

Für den Anfang der Referenz vollständige Code gibt die folgende Ausgabe: Geben Sie hier die Bildbeschreibung ein

Azr
quelle