{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Embed in Qt\n\nSimple Qt application embedding Matplotlib canvases. This program will work\nequally well using any Qt binding (PyQt6, PySide6, PyQt5, PySide2). The\nbinding can be selected by setting the :envvar:`QT_API` environment variable to\nthe binding name, or by first importing it.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import sys\nimport time\n\nimport numpy as np\n\nfrom matplotlib.backends.backend_qtagg import FigureCanvas\nfrom matplotlib.backends.backend_qtagg import \\\n NavigationToolbar2QT as NavigationToolbar\nfrom matplotlib.backends.qt_compat import QtWidgets\nfrom matplotlib.figure import Figure\n\n\nclass ApplicationWindow(QtWidgets.QMainWindow):\n def __init__(self):\n super().__init__()\n self._main = QtWidgets.QWidget()\n self.setCentralWidget(self._main)\n layout = QtWidgets.QVBoxLayout(self._main)\n\n static_canvas = FigureCanvas(Figure(figsize=(5, 3)))\n # Ideally one would use self.addToolBar here, but it is slightly\n # incompatible between PyQt6 and other bindings, so we just add the\n # toolbar as a plain widget instead.\n layout.addWidget(NavigationToolbar(static_canvas, self))\n layout.addWidget(static_canvas)\n\n dynamic_canvas = FigureCanvas(Figure(figsize=(5, 3)))\n layout.addWidget(dynamic_canvas)\n layout.addWidget(NavigationToolbar(dynamic_canvas, self))\n\n self._static_ax = static_canvas.figure.subplots()\n t = np.linspace(0, 10, 501)\n self._static_ax.plot(t, np.tan(t), \".\")\n\n self._dynamic_ax = dynamic_canvas.figure.subplots()\n # Set up a Line2D.\n self.xdata = np.linspace(0, 10, 101)\n self._update_ydata()\n self._line, = self._dynamic_ax.plot(self.xdata, self.ydata)\n # The below two timers must be attributes of self, so that the garbage\n # collector won't clean them after we finish with __init__...\n\n # The data retrieval may be fast as possible (Using QRunnable could be\n # even faster).\n self.data_timer = dynamic_canvas.new_timer(1)\n self.data_timer.add_callback(self._update_ydata)\n self.data_timer.start()\n # Drawing at 50Hz should be fast enough for the GUI to feel smooth, and\n # not too fast for the GUI to be overloaded with events that need to be\n # processed while the GUI element is changed.\n self.drawing_timer = dynamic_canvas.new_timer(20)\n self.drawing_timer.add_callback(self._update_canvas)\n self.drawing_timer.start()\n\n def _update_ydata(self):\n # Shift the sinusoid as a function of time.\n self.ydata = np.sin(self.xdata + time.time())\n\n def _update_canvas(self):\n self._line.set_data(self.xdata, self.ydata)\n # It should be safe to use the synchronous draw() method for most drawing\n # frequencies, but it is safer to use draw_idle().\n self._line.figure.canvas.draw_idle()\n\n\nif __name__ == \"__main__\":\n # Check whether there is already a running QApplication (e.g., if running\n # from an IDE).\n qapp = QtWidgets.QApplication.instance()\n if not qapp:\n qapp = QtWidgets.QApplication(sys.argv)\n\n app = ApplicationWindow()\n app.show()\n app.activateWindow()\n app.raise_()\n qapp.exec()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.2" } }, "nbformat": 4, "nbformat_minor": 0 }