2

I have to use MatPlotlib in my project. However, I need to design QML Application in PyQt5 and as I understand matplotlib plots are Widgets. So, I need to use matplotlib plots inside QML.

My question is that Is there a way to display an interactive matplotlib plot in QML? (by interactive I mean not just a figure that has been saved as an image, ideally with the standard toolbar for zoom etc.)

In here, it asked before but it isn't answered. Can someone help me?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Hilal Köktürk
  • 75
  • 1
  • 10

1 Answers1

-1

If you can live with widgets, it is not that much different from PyQT4. This answer has been greatly inspired by this thread.

The PyQT5-compatible code:

import sys, random

from PyQt5.QtWidgets import (
    QMainWindow,
    QApplication,
    QWidget,
    QVBoxLayout,
    QPushButton,
    QHBoxLayout,
)

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


class AppForm(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)

        # The main_frame keeps all widgets on itself
        self.main_frame = QWidget()

        # Create the interactive matplotlib  figure
        self.fig = Figure((10.0, 16.0), dpi=100)

        # Create figure canvas that gets a reference to self.fig
        # in its __init__
        self.canvas = FigureCanvas(self.fig)
        self.ax = self.fig.add_subplot(111)

        # Create the matplotlib navigation toolbar
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)

        # VBox (V for vertical) where the canvas is placed above the toolbar
        plotVbox = QVBoxLayout()
        plotVbox.addWidget(self.canvas)
        plotVbox.addWidget(self.mpl_toolbar)

        # Another VBox with a button, could eventually hold more
        # vertically ordered buttons
        controls = QVBoxLayout()
        self.button = QPushButton("Refresh")
        self.button.clicked.connect(self.refresh)
        controls.addWidget(self.button)

        # HBox (h for horizontal) where the
        # controls VBox with buttons is on the left
        # and the VBox with the plot is on the riht
        hbox = QHBoxLayout()
        hbox.addLayout(controls)
        hbox.addLayout(plotVbox)

        self.main_frame.setLayout(hbox)
        self.setCentralWidget(self.main_frame)

    def refresh(self):
        """
        Here, the functionality of the 'Refresh' button is implemented.
        Note that we do not return anything, instead we modify the state 
        of the AppForm instance.
        """
        self.ax.clear()
        x = [random.random() for i in range(10)]
        y = [random.random() for i in range(10)]
        self.ax.plot(x, y, "o")
        self.canvas.draw()


def main():
    """
    Open the main window.
    """
    app = QApplication(sys.argv)
    form = AppForm()
    form.show()
    app.exec_()


if __name__ == "__main__":
    main()
Jan Vorac
  • 71
  • 6
  • Thank you for your reply but I need to use with QML not with Widgets. How can I do it? – Hilal Köktürk Feb 13 '20 at 07:47
  • Btw, if you replace `from PyQt5.QtWidgets` with `from PySide2.QtWidgets`, it works as well. You may prefer PySide2 because it's LGPL and it is now the "official Qt for python." – Jan Vorac Feb 13 '20 at 07:54
  • OK, sorry. I have done something like this using the UI file exported by Qt designer by leaving a blank field (QVBoxLayout) which I then filled in in the python part. I guess it should be possible also with QML, but I'm struggling to make QML run on my machine... – Jan Vorac Feb 13 '20 at 11:36