{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Interactive plotting with PyQt\n", "\n", "PyQt integrates well with matplotlib collections, so that collections created through the pandapower plotting module can be embedded into PyQt widgets to create interactive plots or even whole applications.\n", "\n", "This is an example for a slider widget that allows to change the scaling of load and generation in the grid and analyse the power flows in the network in real time. The buses can also be clicked on for a little info window:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import sys\n", "from PyQt5.QtCore import *\n", "from PyQt5.QtGui import *\n", "from PyQt5.QtWidgets import *\n", "from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas\n", "\n", "import pandapower.plotting as plot\n", "import pandapower as pp\n", "import matplotlib.pyplot as plt\n", "\n", "class SliderWidget(QWidget):\n", " def __init__(self, net):\n", " super().__init__()\n", " self.net = net\n", " self.layout = QVBoxLayout()\n", " self.initialize_netplot()\n", " self.initialize_slider()\n", " self.setWindowTitle(\"PyQt with pandapower Demo\")\n", " self.setLayout(self.layout)\n", "\n", " def initialize_netplot(self):\n", " self.net.line_geodata.drop(set(net.line_geodata.index) - set(net.line.index), inplace=True)\n", " cmap, norm = plot.cmap_continuous([(0.97, \"blue\"), (1.0, \"green\"), (1.03, \"red\")])\n", " self.bc = plot.create_bus_collection(net, size=90, zorder=2, cmap=cmap, norm=norm, picker=True,\n", " infofunc=lambda x: \"This is bus %s\"%net.bus.name.at[x])\n", " cmap, norm = plot.cmap_continuous([(20, \"green\"), (50, \"yellow\"), (60, \"red\")])\n", " self.lc = plot.create_line_collection(net, zorder=1, cmap=cmap, norm=norm, linewidths=2,\n", " infofunc=lambda x: \"This is line %s\"%net.line.name.at[x])\n", " self.fig, self.ax = plt.subplots()\n", " plot.draw_collections([self.bc, self.lc], ax=self.ax)\n", " plt.close()\n", " self.canvas = FigureCanvas(self.fig)\n", " self.canvas.mpl_connect('pick_event', self.pick_event)\n", " self.canvas.draw()\n", " self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)\n", " self.layout.addWidget(self.canvas)\n", " \n", " def initialize_slider(self):\n", " self.sliders = {}\n", " for element in [\"load\", \"sgen\"]:\n", " frame = QWidget()\n", " layout = QHBoxLayout()\n", " layout.addWidget(QLabel(\"scaling %s\"%element))\n", " self.sliders[element] = QSlider(Qt.Horizontal, value=50)\n", " self.sliders[element].valueChanged.connect(self.slider_changed)\n", " layout.addWidget(self.sliders[element])\n", " frame.setLayout(layout)\n", " self.layout.addWidget(frame)\n", " \n", " def slider_changed(self):\n", " for element, slider in self.sliders.items():\n", " self.net[element].scaling = slider.value() / 100.\n", " pp.runpp(self.net)\n", " self.ax.collections[0].set_array(self.net.res_bus.vm_pu.values)\n", " self.ax.collections[1].set_array(self.net.res_line.loading_percent.values)\n", " self.canvas.draw()\n", "\n", " def pick_event(self, event):\n", " idx = event.ind[0]\n", " collection = event.artist\n", " self.info = QLabel()\n", " self.info.setText(collection.info[idx])\n", " self.info.show()" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "def main(net):\n", " app = QApplication(sys.argv)\n", " ex = SliderWidget(net)\n", " ex.showMaximized()\n", " sys.exit(app.exec_())" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "ename": "SystemExit", "evalue": "0", "output_type": "error", "traceback": [ "An exception has occurred, use %tb to see the full traceback.\n", "\u001b[1;31mSystemExit\u001b[0m\u001b[1;31m:\u001b[0m 0\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "C:\\Users\\mmilovic\\anaconda3\\lib\\site-packages\\IPython\\core\\interactiveshell.py:3465: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.\n", " warn(\"To exit: use 'exit', 'quit', or Ctrl-D.\", stacklevel=1)\n" ] } ], "source": [ "from pandapower.networks import mv_oberrhein\n", "net = mv_oberrhein()\n", "main(net)" ] } ], "metadata": { "execution": { "allow_errors": true, "timeout": 300 }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.9.13" } }, "nbformat": 4, "nbformat_minor": 2 }