{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Plotting Pandapower Networks" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "This tutorial shows you how to plot pandapower networks. \n", "\n", "We use matplotlib collections to plot the stations or lines in the network. There are different types of elements in matplotlib, like lines, circles, rectangles etc. These elements are bundled into collections, where one objects holds many elements of the same type (see matplotlib documentation: http://matplotlib.org/api/collections_api.html).\n", "\n", "The plotting module provides several functions that create collections from pandapower networks. In this interactive tutorial, we show you how to use these functions to plot networks." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Simple Plotting\n", "\n", "There is a convenience function that allows you to plot networks fast without having to gain an in depths understanding of the pandapower plotting module. The simple_plot function can be called as follows:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2025-10-20T09:19:56.040624Z", "start_time": "2025-10-20T09:19:52.392741Z" } }, "outputs": [], "source": [ "import numpy as np\n", "import geojson\n", "from pandapower.networks import mv_oberrhein\n", "from pandapower.topology.create_graph import create_nxgraph\n", "from pandapower.topology.graph_searches import calc_distance_to_bus, connected_components\n", "from pandapower.plotting.simple_plot import simple_plot\n", "from pandapower.run import runpp\n", "from pandapower.plotting.plotting_toolbox import get_collection_sizes\n", "from pandapower.plotting import create_line_collection, create_bus_collection, draw_collections, create_annotation_collection" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2025-10-20T09:19:59.411100Z", "start_time": "2025-10-20T09:19:56.045609Z" } }, "outputs": [], "source": [ "# load example net (IEEE 9 buses)\n", "net = mv_oberrhein()\n", "# simple plot of net with existing geocoordinates or generated artificial geocoordinates\n", "simple_plot(net, show_plot=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This function plots geodata if it is available and generates generic geodata if none is available. Note that you need the igraph package to generate geocoordinates (see last chapter of this tutorial).\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plotting Collections" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you want to have full control over the layout of your plot, you can individually create and plot collections with the pandapower plotting module." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2025-10-20T09:19:59.426670Z", "start_time": "2025-10-20T09:19:59.418672Z" } }, "outputs": [], "source": [ "try:\n", " import seaborn\n", " colors = seaborn.color_palette()\n", "except:\n", " colors = [\"b\", \"g\", \"r\", \"c\", \"y\"]\n", "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First, we plot only the lines and buses of an example network. This is done by creating a line collection for all lines and a bus collection for all buses. We then plot both collections with the draw_collections function:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2025-10-20T09:20:00.102904Z", "start_time": "2025-10-20T09:19:59.437323Z" }, "scrolled": true }, "outputs": [], "source": [ "net = mv_oberrhein()\n", "sizes = get_collection_sizes(net)\n", "\n", "lc = create_line_collection(net, net.line.index, color=\"grey\", zorder=1) #create lines\n", "bc = create_bus_collection(net, net.bus.index, size=sizes['bus'], color=colors[0], zorder=2) #create buses\n", "draw_collections([lc, bc], figsize=(8,6)) # plot lines and buses" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot Bus IDs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Bus indices (names, or other annotations) can be plotted by creating an additional collection.\n", "\n", "In this example, we plot all bus indices. Therefore we create a new collection (bic) with create_annotation_collection.\n", "For this we need a list of strings (Texts) which contain the texts to plot and their coordinates (coords, tuples of coordinates)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2025-10-20T09:20:01.348008Z", "start_time": "2025-10-20T09:20:00.111211Z" } }, "outputs": [], "source": [ "buses = net.bus.index.tolist() # list of all bus indices\n", "coords = net.bus.geo.apply(geojson.loads).apply(geojson.utils.coords).apply(next).values\n", "\n", "bic = create_annotation_collection(size=sizes['bus'] * 1.5, texts=np.char.mod('%d', buses), coords=coords, zorder=10, color=colors[1])\n", "draw_collections([lc, bc, bic], figsize=(80,60)) # plot lines, buses and bus indices" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Highlighting" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Specific lines or buses can be highlighted by creating extra line collections in different colors.\n", "\n", "In this example, we plot lines that are longer than 2 km green and buses with a voltage below 0.98 pu red.\n", "\n", "First, we create a line collection for all lines in grey and a line collection for only the long lines in green:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2025-10-20T09:20:02.108554Z", "start_time": "2025-10-20T09:20:01.368010Z" } }, "outputs": [], "source": [ "net = mv_oberrhein()\n", "long_lines = net.line[net.line.length_km > 2.].index\n", "lc = create_line_collection(net, net.line.index, color=\"grey\", zorder=1)\n", "lcl = create_line_collection(net, long_lines, color=\"g\", zorder=2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that the zorder is higher for the long line collection. This ensures that the green line collection is plotted over the grey line collection.\n", "\n", "We then conduct a loadflow and create bus collections in the same way:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2025-10-20T09:20:02.233539Z", "start_time": "2025-10-20T09:20:02.116536Z" } }, "outputs": [], "source": [ "runpp(net)\n", "low_voltage_buses = net.res_bus[net.res_bus.vm_pu < 0.98].index\n", "bc = create_bus_collection(net, net.bus.index, size=sizes['bus'], color=colors[0], zorder=10)\n", "bch = create_bus_collection(net, low_voltage_buses, size=sizes['bus'], color=colors[2], zorder=11)\n", "draw_collections([lc, lcl, bc, bch], figsize=(8,6))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another way to highlight something is to use a different shape using the patch_type argument of the create_bus collection. You can for example mark the slack bus with a rectangle shape like this:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2025-10-20T09:20:02.901540Z", "start_time": "2025-10-20T09:20:02.239540Z" } }, "outputs": [], "source": [ "net = mv_oberrhein()\n", "lc = create_line_collection(net, net.line.index, color=\"grey\", zorder=1) #create lines\n", "bc = create_bus_collection(net, net.bus.index, size=sizes['bus'], color=colors[0], zorder=2) #create buses\n", "sc = create_bus_collection(net, net.ext_grid.bus.values, patch_type=\"rect\", size=sizes['bus'], color=colors[4], zorder=11)\n", "draw_collections([lc, bc, sc], figsize=(8,6)) # plot lines and buses" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Highlighting with the Topology Package" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Combining the [topology package](topology.ipynb) with the plotting package allows highlighting of structural features of the network. For example, we can highlight all buses closer than 5 km to a transformer station:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2025-10-20T09:20:03.521755Z", "start_time": "2025-10-20T09:20:02.910534Z" } }, "outputs": [], "source": [ "net = mv_oberrhein()\n", "close_buses = set()\n", "for slack in net.ext_grid.bus:\n", " d = calc_distance_to_bus(net, slack)\n", " close_buses |= set(d[d < 5].index)\n", "\n", "bc = create_bus_collection(net, net.bus.index, size=sizes['bus'], color=colors[0], zorder=1)\n", "bch = create_bus_collection(net, close_buses, size=sizes['bus'], color=colors[2], zorder=2)\n", "lc = create_line_collection(net, net.line.index, zorder=1, color=\"grey\")\n", "sc = create_bus_collection(net, net.ext_grid.bus.values, patch_type=\"rect\", size=sizes['bus'], color=colors[4], zorder=11)\n", "draw_collections([lc, bc, bch, sc], figsize=(8,6))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or to highlight the radiality of the network, plot the seperate feeders in different colors:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2025-10-20T09:20:04.402842Z", "start_time": "2025-10-20T09:20:03.536178Z" } }, "outputs": [], "source": [ "net = mv_oberrhein()\n", "mg = create_nxgraph(net, nogobuses=set(net.trafo.lv_bus.values) | set(net.trafo.hv_bus.values))\n", "collections = []\n", "for color, area in zip(colors, connected_components(mg)):\n", " collections.append(create_bus_collection(net, area, size=sizes['bus'], color=color, zorder=2))\n", "collections.append(create_line_collection(net, net.line.index, zorder=1, color=\"grey\"))\n", "collections.append(create_bus_collection(net, net.ext_grid.bus.values, patch_type=\"rect\", size=sizes['bus'],\n", " color=colors[4], zorder=11))\n", "draw_collections(collections, figsize=(8,6))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Direct Line Connections" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Line collections are plotted with the geographical coordinates of the lines that are stored in net.line_geodata by default. You can also plot lines as direct connections between the buses, by calling the create_line_collection function with use_bus_geodata=True:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2025-10-20T09:20:05.165906Z", "start_time": "2025-10-20T09:20:04.409851Z" }, "scrolled": false }, "outputs": [], "source": [ "net = mv_oberrhein()\n", "bc = create_bus_collection(net, net.bus.index, size=sizes['bus'], color=colors[0], zorder=10)\n", "lcd = create_line_collection(net, net.line.index, use_bus_geodata=True, color=\"grey\", linewidths=2.)\n", "sc = create_bus_collection(net, net.ext_grid.bus.values, patch_type=\"rect\", size=sizes['bus'],\n", " color=colors[4], zorder=11)\n", "draw_collections([lcd, bc, sc])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a comparison, here are the lines with direct connections (solid) and the line trails from line_geodata (dashed):" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2025-10-20T09:20:05.823615Z", "start_time": "2025-10-20T09:20:05.174886Z" } }, "outputs": [], "source": [ "net = mv_oberrhein()\n", "bc = create_bus_collection(net, net.bus.index, size=sizes['bus'], color=colors[0], zorder=10)\n", "lcd = create_line_collection(net, lines=net.line.index, color=\"grey\",alpha=0.8, linewidths=2., use_bus_geodata=True)\n", "lc = create_line_collection(net, lines=net.line.index, color=\"grey\",alpha=0.8, linestyles=\"dashed\", linewidths=2.)\n", "sc = create_bus_collection(net, net.ext_grid.bus.values, patch_type=\"rect\", size=sizes['bus'],\n", " color=colors[4], zorder=11)\n", "draw_collections([lc, lcd, bc, sc])" ] } ], "metadata": { "anaconda-cloud": {}, "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" } }, "nbformat": 4, "nbformat_minor": 1 }