{ "cells": [ { "cell_type": "markdown", "id": "ed13a6b8-1d5b-4ce0-9cd4-b81bac7b07dd", "metadata": {}, "source": [ "# Plotting" ] }, { "cell_type": "markdown", "id": "fcfe6476", "metadata": {}, "source": [ "This notebook explains the main plotting functions available for a `WindFarmNetwork` object.\n", "\n", "These plotting methods are natively optimized to return high-performance, lightweight, and modern vector **SVG representations** (`svgplot`/`svgpplot`) by default inside notebooks. However, they also seamlessly switch to **Matplotlib backends** (`gplot`/`pplot`) when you supply a custom target axes (e.g. `ax=...`), giving you the best of both worlds: clean direct display and advanced layout customizability." ] }, { "cell_type": "markdown", "id": "3bad0d73", "metadata": {}, "source": [ "## Import required modules" ] }, { "cell_type": "code", "execution_count": 1, "id": "b0f61785-6be5-4a0f-8282-5c17f4cc28ad", "metadata": {}, "outputs": [], "source": [ "from optiwindnet.api import WindFarmNetwork, load_repository" ] }, { "cell_type": "code", "execution_count": 2, "id": "2f7f3fb1", "metadata": {}, "outputs": [], "source": [ "# Display figures as SVG in Jupyter notebooks\n", "%config InlineBackend.figure_formats = ['svg']" ] }, { "cell_type": "markdown", "id": "cb7f8713-8170-4ada-a2a9-849fbd88771f", "metadata": {}, "source": [ "## Create a sample network" ] }, { "cell_type": "markdown", "id": "3f8789d4-5f85-4e50-a7b6-dd9b57f0e4a2", "metadata": {}, "source": [ "> Note: `load_repository()` loads multiple locations from a given path. If no path is given, it loads the built-in locations (more details in [Load Location Data Repositories](a03_load_repositories.ipynb))." ] }, { "cell_type": "code", "execution_count": 3, "id": "4e702047", "metadata": {}, "outputs": [], "source": [ "locations = load_repository()\n", "wfn = WindFarmNetwork(L=locations.anholt, cables=[(2, 1500.0), (5, 1800.0)])" ] }, { "cell_type": "markdown", "id": "5fab2b53", "metadata": {}, "source": [ "## Plot location geometry (`L`):\n", "\n", "`L` contains only the **raw location data**, such as turbine and substation coordinates, borders, and obstacles, **without any links or connections** between nodes.\n", "\n", "As a result, `wfn.plot_location()` will appear as an **edgeless graph**, showing only the borders and node elements without network links/edges. Turbines are plotted as *circles*, and substations as *squares*.\n", "\n", "This plot is useful to check if the location data was correctly loaded into the `WindFarmNetwork()` instance, before running the optimization." ] }, { "cell_type": "code", "execution_count": 4, "id": "f88ccb3c", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn.plot_location()" ] }, { "cell_type": "markdown", "id": "e01d4da1", "metadata": {}, "source": [ ">**Tip**: In a notebook, just put `wfn` as the last line of a cell for plotting G.\n", ">\n", ">* Before optimization (no `G` yet), it renders the location geometry `L`.\n", ">* If `G` exists (e.g. after a call to `optimize()`), it automatically renders `G`." ] }, { "cell_type": "code", "execution_count": 5, "id": "eeb09ee1", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn" ] }, { "cell_type": "markdown", "id": "eec3ae91-1043-48cf-96ed-dfd3304916bb", "metadata": {}, "source": [ "## Optimize" ] }, { "cell_type": "markdown", "id": "13554c48", "metadata": {}, "source": [ "To plot and visualize the optimized network, an optimization needs to be performed first. Here, the default router (`Heuristics-Esau_Williams`) is used." ] }, { "cell_type": "code", "execution_count": 6, "id": "f888963b", "metadata": {}, "outputs": [], "source": [ "res = wfn.optimize()" ] }, { "cell_type": "markdown", "id": "b5a529f4-edb9-48ac-8aa0-0ce46f3002e0", "metadata": {}, "source": [ "## Plot the Optimized Network Graph" ] }, { "cell_type": "markdown", "id": "9a43d824", "metadata": {}, "source": [ "The optimized network graph (G) represents the optimized network with actual routes.\n", "\n", "Accordingly, `wfn.plot()` displays the routes for selected links in the **optimized network**. The detoured routes are displayed via dashed lines. Detours are the routes created to resolve crossing feeders.\n", "\n", "Turbines that belong to the same subtree are assigned the same color. Each cable type is represented with a distinct line thickness (which gets thicker as the cable capacity increases)." ] }, { "cell_type": "code", "execution_count": 7, "id": "883efe11", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "363 646 266 €Σλ = 208 761 m(+0) OSS: 23κ = 5, T = 111" ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn.plot()" ] }, { "cell_type": "markdown", "id": "8814596b", "metadata": {}, "source": [ "> ! Reminder: In a notebook, we can plot the optimized network simply by calling `wfn`:" ] }, { "cell_type": "code", "execution_count": 8, "id": "29dcc789", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "363 646 266 €Σλ = 208 761 m(+0) OSS: 23κ = 5, T = 111" ], "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn" ] }, { "cell_type": "markdown", "id": "69938619-68ab-46a9-a819-e8254e2fe092", "metadata": {}, "source": [ "## Plot in a pre-existing axes" ] }, { "cell_type": "code", "execution_count": 9, "id": "46890d30-d033-4da5-a513-1f25b7e91766", "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "plt.rcParams['svg.fonttype'] = 'none'" ] }, { "cell_type": "markdown", "id": "9cc236bf-61b1-43b7-90d0-a866e32eb1f2", "metadata": {}, "source": [ "It is also possible to provide a pre-existing `plt.Axes` object within a Matplotlib figure:\n", "\n", "> **Tip:** When you pass the `ax` keyword argument to any `wfn` plotting method, it automatically switches under the hood from the native SVG generator to the Matplotlib backend (`gplot`/`pplot`). This allows you to combine and structure multiple plots in standard Matplotlib subplots.\n", "\n", "> **Shortcut (No Imports):** If you want to use the Matplotlib backend (`gplot`/`pplot`) but don't want to import Matplotlib/Pyplot in your code, you can simply pass `ax=None` (e.g., `ax = wfn.plot(ax=None)`). The plotting method will detect the `ax` key, switch to the Matplotlib backend, internally import Matplotlib to create a new figure and axes, and return the active `plt.Axes` object." ] }, { "cell_type": "code", "execution_count": 10, "id": "64669b15", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", " \n", " image/svg+xml\n", " \n", " \n", " OptiWindNet\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " κ = 5, T = 111\n", " (+0) OSS: 23\n", " Σλ = 208 761 m\n", " 363 646 266 €\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n" ], "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig, (ax1, ax2) = plt.subplots(1, 2, facecolor='none', figsize=(8, 4))\n", "\n", "wfn.plot_location(ax=ax1)\n", "wfn.plot(ax=ax2, legend=False)" ] }, { "cell_type": "markdown", "id": "bc70750c", "metadata": {}, "source": [ "## 📊 Optional parameters" ] }, { "cell_type": "markdown", "id": "47537ebb-91fe-41cd-b997-0ed290a697ec", "metadata": {}, "source": [ "### 🏷️ `node_tag` (text labels)" ] }, { "cell_type": "markdown", "id": "f1e56e24-6b4e-4d63-b24a-73e69eb51652", "metadata": {}, "source": [ "Node tags make it easier to identify each turbine and substation in the plot. Here is a table of possible values and their effects:\n", "\n", "| `node_tag` value | Behavior |\n", "| -------------- | --------------------------------------------------------------------------- |\n", "| `node_tag=True` | Node id number used as tag (id is set from the order of appearance in data, starting from 0 for turbines and negative for substations).|\n", "| `node_tag='label'` | Node label used as tag. Labels can be defined in the `.yaml` file or as a node tag in `.osm.pbf`. Programmatically, labels can be assigned as node attribute: `G.nodes[id]['label'] = 'some_label'`|\n", "| `node_tag='load'` | Use the value of the load exported by the node.|\n", "| `node_tag='custom_attribute'` | Use the value of `custom_attribute` from node. |" ] }, { "cell_type": "markdown", "id": "a41f283c-8d65-4f29-a5e7-2ef05f0ecbf3", "metadata": {}, "source": [ "> **Note**: The default symbol sizes are optimized for tags with up to **three characters** using the default font size, longer tags might not fit inside the symbol and become difficult to read." ] }, { "cell_type": "code", "execution_count": 11, "id": "6a4b7e32", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "0123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110-1363 646 266 €Σλ = 208 761 m(+0) OSS: 23κ = 5, T = 111" ], "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn.plot(node_tag=True)" ] }, { "cell_type": "markdown", "id": "b840b66f-3a7e-4c49-9e66-a9a9d80bb5f1", "metadata": {}, "source": [ "**Labels in location data files**" ] }, { "cell_type": "markdown", "id": "27aa4058-0985-45fd-b701-dfd9dbdb5a3a", "metadata": {}, "source": [ "Labels can be defined in both `.yaml` and `.osm.pbf` files." ] }, { "cell_type": "markdown", "id": "9037985d-df5d-4a91-a5e5-399bde59ec1c", "metadata": {}, "source": [ "- **`.yaml` files:**\n", "Any identifier placed *before* the coordinates is loaded as a node label (`label` attribute).\n", "Example:\n", "\n", "```yaml\n", "SUBSTATIONS: |-\n", " OSS 56°35.748'N 11°09.174'E\n", "\n", "TURBINES: |-\n", " A01 56°30.477'N 11°11.026'E\n", " A02 56°30.810'N 11°11.078'E\n", "```\n", "\n", "Here, `OSS`, `A01` and `A02` are node labels." ] }, { "cell_type": "markdown", "id": "c218572d", "metadata": {}, "source": [ "- **`.osm.pbf` files:**\n", "Node tags `'name'` or `'ref'` are loaded as a node label (`label` attribute).\n", "\n", "Example (OSM XML structure):\n", "\n", "```xml\n", "\n", " \n", " \n", "\n", "```\n", "\n", "In this case, the substation node will be tagged with the label `'OSS'`." ] }, { "cell_type": "code", "execution_count": 12, "id": "4e41efbe-054c-4949-9880-95c9029e3017", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "WTGOSScornerdetourrouteA01A02A03A04A05A06A07A08A09A10A11A12A13A14A15A16A17A18A19A20A22A23A24A25A26A27A28A29A30A31B01C01C02C03C04C05C06C07C09C10C12C31D01E01F01F02F03F04F05F06F07F08F09F10F11F12F13F14F23F24F25F26F27F28F29G01H01I01I02I03I04I05I07I08I10I28J01K01L01L02L03L04L05L06M01P01P02P03P04P05P06P07P08P09P10P11P12P13P15P16P17P19P20P21P22P23P24P25P26P27P28OSS" ], "text/plain": [ "" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn.plot(node_tag='label', infobox=False, legend=True)" ] }, { "cell_type": "code", "execution_count": 13, "id": "dd74ab60", "metadata": {}, "outputs": [], "source": [ "wfn.L.nodes[0]['example_label']='T0'" ] }, { "cell_type": "code", "execution_count": 14, "id": "dc6d5497", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "T0" ], "text/plain": [ "" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn.plot_location(node_tag='example_label')" ] }, { "cell_type": "markdown", "id": "2a5748af-1d93-4920-a952-3e93e27c8d50", "metadata": {}, "source": [ "The nodes can also be tagged with the amount of power (normalized by the turbine nominal power) they export towards the substation:\n", "- The turbine tag represents the number of turbines exporting power through it, (i.e. number of turbines upstream, including itself).\n", "- The substation tag represents the total number of connected turbines." ] }, { "cell_type": "code", "execution_count": 15, "id": "3c8bbff6-e73b-44f8-932f-4d485763faa8", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "123451234512534515215454321543124512344522312512351251554321154314151234124143212345112345123451313215432154321111363 646 266 €Σλ = 208 761 m(+0) OSS: 23κ = 5, T = 111" ], "text/plain": [ "" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn.plot(node_tag='load')" ] }, { "cell_type": "markdown", "id": "88b49207-5bf5-4dd0-b22a-e1e035335d91", "metadata": {}, "source": [ "### 🎨 `dark` (color theme)" ] }, { "cell_type": "markdown", "id": "fbbf39e7-b228-4142-93d5-1f757d8c0e5f", "metadata": {}, "source": [ "The plotting methods try to match the operating system's theme via Python package `darkdetect`. This package detects the system's theme and not JupyterLab's theme, so it may lead to non-ideal results if they do not match.\n", "\n", "The example notebooks are created from a dark-themed system, but the figures might have a light background when the notebooks are run on a different computer.\n", "\n", "The theme can be enforced programmatically by setting the argument `dark` to `True` or `False`:" ] }, { "cell_type": "code", "execution_count": 16, "id": "09b9bc08-7048-4116-b5d2-0226ebeb2037", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "363 646 266 €Σλ = 208 761 m(+0) OSS: 23κ = 5, T = 111" ], "text/plain": [ "" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn.plot(dark=False)" ] }, { "cell_type": "markdown", "id": "334b548e-acd4-41c4-93e0-d715b1b0c5f4", "metadata": {}, "source": [ "### 🔄 `landscape_angle` (rotation)" ] }, { "cell_type": "markdown", "id": "f0f10ebf-ffcb-4cd9-85fc-c95b7d0a2416", "metadata": {}, "source": [ "Each location included in `OptiWindNet` has a graph attribute called `landscape_angle`." ] }, { "cell_type": "code", "execution_count": 17, "id": "c38128f0-22b3-400b-9604-48d423d6c25e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "81.8" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn.L.graph['landscape_angle']" ] }, { "cell_type": "markdown", "id": "78a9cadd-93d2-4fa8-a37f-f08947b6fa3e", "metadata": {}, "source": [ "This is the angle by which to rotate the site so as to orient the widest dimension horizontally, which suits a landscape figure (as opposed to portrait). For orienting the location so that the north is up, pass the argument `landscape=False` (or set `wfn.L.graph['landscape_angle'] = 0`)." ] }, { "cell_type": "code", "execution_count": 18, "id": "5a69abdd", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "363 646 266 €Σλ = 208 761 m(+0) OSS: 23κ = 5, T = 111" ], "text/plain": [ "" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn.plot(landscape=False)" ] }, { "cell_type": "markdown", "id": "f94d14b7", "metadata": {}, "source": [ "## Plotting Auxiliary Graphs" ] }, { "cell_type": "markdown", "id": "ef306c5b", "metadata": {}, "source": [ "Of the **five plot methods**, `wfn.plot_location()` and `wfn.plot()` have been presented above.\n", "\n", "The remaining plot methods are for the auxiliary graphs `navigation_mesh`, `available_links`, and `selected_links`, which are relevant mainly for **debugging** and **development**. For a more detailed explanation of their meaning and purpose, consult the [paper](https://doi.org/10.1016/j.ejor.2025.07.069)." ] }, { "cell_type": "markdown", "id": "32641de9", "metadata": {}, "source": [ "### Navigation mesh" ] }, { "cell_type": "markdown", "id": "2a6bf78f", "metadata": {}, "source": [ "The *navigation mesh* is a triangulation of all vertices (coordinate pairs that define either turbines, substations or obstacles) of the location. An additional triangle is added (the supertriangle) such as to contain all vertices inside it (it does not fit in the plot, but can be inferred by the edges interrupted at the figure's borders). This mesh is obtained via a **constrained Delaunay triangulation** and stored as a planar embedding in `wfn.P`." ] }, { "cell_type": "code", "execution_count": 19, "id": "494da4c3", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn.plot_navigation_mesh()" ] }, { "cell_type": "markdown", "id": "0e502746", "metadata": {}, "source": [ "### Available Links" ] }, { "cell_type": "markdown", "id": "773fbc6e-3a04-4b04-9ddb-fe2b3beb9d98", "metadata": {}, "source": [ "The *available links* graph is derived from the **Delaunay triangulation** of the turbine and substation vertices, extended with the additional **diagonal links**. This graph is stored in `wfn.A` and represents the **search space**, except for the star links from each substation to each turbine (which are ommited for clarity). The optimization algorithm selects a subset of the links in this graph." ] }, { "cell_type": "markdown", "id": "ed2e8809", "metadata": {}, "source": [ "The resulting plot encodes the available links using different **line styles and colors** to distinguish link types:\n", "\n", "- **Line style:**\n", " - **Solid lines**: direct Delaunay links\n", " - **Dashed lines**: diagonal links\n", "- **Line color:**\n", " - in the **dark** theme:\n", " * **Cyan**: direct links\n", " * **Green**: obstructed links\n", " - in the **light** theme:\n", " * **Green**: direct links\n", " * **Red**: obstructed links" ] }, { "cell_type": "code", "execution_count": 20, "id": "ed782ca3", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn.plot_available_links()" ] }, { "cell_type": "markdown", "id": "f3e63aae", "metadata": {}, "source": [ "### Selected Links" ] }, { "cell_type": "markdown", "id": "56e65d53", "metadata": {}, "source": [ "`wfn.plot_selected_links()` displays the **links selected** from the available links by the router algorithm." ] }, { "cell_type": "code", "execution_count": 21, "id": "2d98f576", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "355 417 487 €Σλ = 204 189 m(+0) OSS: 23κ = 5, T = 111" ], "text/plain": [ "" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn.plot_selected_links()" ] }, { "cell_type": "markdown", "id": "1f812815", "metadata": {}, "source": [ "To clarify the difference between `wfn.plot_selected_links()` and `wfn.plot()`, it's important to distinguish between a *link* and a *route*:\n", "\n", "- **link**: represents the **electrical connection** between two nodes (e.g., turbine to substation), without considering the actual implementation of the connection. (*Displayed by* `wfn.plot_selected_links()`)\n", "- **route**: represents the **geographical path** for the cable to implement a link, including **contours** to go around borders or obstacles and **detours** to avoid cable crossings by the feeders. (*Displayed by* `wfn.plot()`)" ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }