{
  "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 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.14.6"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}