Skip to content

Commit

Permalink
Adds map-viewer widget (#13)
Browse files Browse the repository at this point in the history
* adds a map-viewer widget based on the network-map-viewer component (from powsybl-diagram-viewer)
* adds the VL picker and the VL nominal voltage filter to the map widget; adds a widget callback mechanism so that it is possible to intercept picked VL from python
* adds a map tab to the network explorer
* map widget can also use the line positions extensions from the network when displaying lines (optional feature)
* adds parameters for displaying ids or names, and filter the top n nominal vls in the map widget; network explorer: activates the SLD tab when a VL level is chosen in the map tab
* adds a map demo notebook
* fixes size of the voltage filter
* updates docs

Signed-off-by: Christian Biasuzzi <christian.biasuzzi@soft.it>
  • Loading branch information
CBiasuzzi authored Sep 3, 2024
1 parent ef08cac commit f5cbcb4
Show file tree
Hide file tree
Showing 21 changed files with 1,203 additions and 126 deletions.
Binary file added docs/_static/img/network_explorer_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/img/network_explorer_4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/img/networkmap_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/img/networkmap_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/getting_started/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ network_explorer(network)
```

Through the network explorer widget you can display NAD and SLD diagrams for a voltage level, selected from the available network's voltage levels, in two dedicated tabs.
A third tab, 'Network map' displays the network's substations and lines on a map.

![getting started demo](/_static/img/getting_started_1.png)

Expand Down
3 changes: 2 additions & 1 deletion docs/user_guide/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# User guide

Pypowsybl-jupyter provides a library of interactive widgets for jupyter, targeted at visualizing network diagrams generated e.g., through PyPowSyBl (network-area diagrams and single-line diagrams).
Pypowsybl-jupyter provides a library of interactive widgets for jupyter, targeted at visualizing network diagrams generated e.g., through PyPowSyBl (network-area diagrams, single-line diagrams, etc.).

This section details the available widgets.

Expand All @@ -11,4 +11,5 @@ network_explorer.md
nad_explorer.md
sld_widget.md
nad_widget.md
network_map_widget.md
```
19 changes: 16 additions & 3 deletions docs/user_guide/network_explorer.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Network explorer widget

Network explorer is interactive network explorer widget, built on pypowsybl-jupyter's widgets (SLD and NAD) and some standard [ipywidgets](https://ipywidgets.readthedocs.io/en/stable/index.html): select lists, tabs, etc.
Network explorer is interactive network explorer widget, built on pypowsybl-jupyter's widgets (SLD, NAD, Network map) and some standard [ipywidgets](https://ipywidgets.readthedocs.io/en/stable/index.html): select lists, tabs, etc.

Through the widget, you can select a voltage level from the list (or search of a specific one using the Filter) and the NAD and SLD diagrams for that voltage level will be displayed in the two "Network Area" and "Single Line" tabs, respectively. Both diagrams can be panned and zoomed.
Through the widget, you can select a voltage level from the list (or search of a specific one using the Filter) and the NAD and SLD diagrams for that voltage level will be displayed in the two "Network Area" and "Single Line" tabs, respectively. Both diagrams can be panned and zoomed. A third tab, 'Network map' displays the network's substations and lines on a map, if substations and lines geo data is available in the network.

The following code, to be run in a notebook, first creates a network, then displays the network explorer on it.

Expand Down Expand Up @@ -31,19 +31,32 @@ By clicking on an arrow in the SLD you can navigate to another voltage level.

Switches can also be clicked, causing their status in the network to change; Please note that, currently, this action does not trigger any computation on the network (e.g., a LF is not automatically run on the network).

## Network map tab

![network-explorer MAP tab](/_static/img/network_explorer_3.png)

The 'Network map' displays the network's substations and lines on a map. The map is empty if the network does not contain geo data.
By clicking on a substation, a list with the substation's voltage levels appears.

![network-explorer MAP tab VLs list](/_static/img/network_explorer_4.png)

A further click on an entry in the list will navigate the explorer to the corresponding voltage level.


## Widget API

Other than the target network, the Network explorer can be customized using additional parameters:

```python
network_explorer(network: Network, vl_id : str = None, use_name:bool = True, depth: int = 0, high_nominal_voltage_bound: float = -1, low_nominal_voltage_bound: float = -1, nad_parameters: NadParameters = None, sld_parameters: SldParameters = None):
network_explorer(network: Network, vl_id : str = None, use_name:bool = True, depth: int = 0, high_nominal_voltage_bound: float = -1, low_nominal_voltage_bound: float = -1, nad_parameters: NadParameters = None, sld_parameters: SldParameters = None, use_line_geodata:bool = False):
```

- vl_id: the starting VL to display. If None, display the first VL from network.get_voltage_levels()
- use_name: when available, display VLs names instead of their ids (default is to use names)
- depth: the diagram depth around the voltage level, controls the size of the sub network. In the SLD tab will be always displayed one diagram, from the VL list currently selected item.
- low_nominal_voltage_bound: low bound to filter voltage level according to nominal voltage
- high_nominal_voltage_bound: high bound to filter voltage level according to nominal voltage
- nominal_voltages_top_tiers_filter: number of nominal voltages to select in the Network map's nominal voltages filter, starting from the highest. -1 means all the nominal voltages.
- nad_parameters: layout properties to adjust the svg rendering for the NAD
- sld_parameters: layout properties to adjust the svg rendering for the SLD
- use_line_geodata: When False (default) the network map tab does not use the network's line geodata extensions; Each line is drawn as a straight line connecting two substations.
55 changes: 55 additions & 0 deletions docs/user_guide/network_map_widget.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Network map widget

Network map is an interactive widget that displays a network's substations and lines on a map.
If the network does not contain geo data (in its substation's and line's IIDM extensions), the map will be empty.
The widget allows you to pan and zoom the map. A filter on the network's nominal voltages list can be used to improve the readability of the map, in case of a large network.

The following code, to be run in a notebook, first creates a network, then displays the Network map widget on it.

```python
import pypowsybl.network as pn
from pypowsybl_jupyter import NetworkMapWidget

# load a CGMES file containing a GL profile (Graphical Layout) and run a LF
network1 = pn.load('./data/MicroGridTestConfiguration_T4_BE_BB_Complete_v2.zip', {'iidm.import.cgmes.post-processors': 'cgmesGLImport'})

NetworkMapWidget(network1)
```

![Network map widget 1](/_static/img/networkmap_1.png)


A click on a substation pops up a list of its VL.

![Network map widget 2](/_static/img/networkmap_2.png)


## Widget API
```python
NetworkMapWidget(network:Network, sub_id:str = None, use_name:bool = True, display_lines:bool = True, use_line_geodata:bool = False, nominal_voltages_top_tiers_filter = -1) -> NetworkMapWidget
```

- network: the input network.
- sub_id: if not None, centers the network on the substation with the given substation id. Default is None.
- use_name: When True (default) the widget displays network's elements names (if available, otherwise their ids); When False, the widget displays network's elements ids.
- display_lines: When True (default) the network lines are displayed on the map. When false, the widget displays only the substations.
- use_line_geodata: When False (default) the widget does not use the network's line geodata extensions; Each line is drawn as a straight line connecting two substations.
- nominal_voltages_top_tiers_filter: filters the elements in the map based on the network's top nominal voltages. N displays the top n nominal voltages; -1 (default) displays all.


## Customize widget's interactions
It is possible to customize the widget's behaviour when one entry is clicked in a substation's voltage levels popup. This feature could be used to create more complex interactions (e.g., by integrating other widgets).

Use these widget's method to register a callback on a specific event:

- on_selectvl

The [network explorer](/user_guide/network_explorer.md) demonstrates the approach.

Example: the code below activate a callback when a VL entry is clicked in the VL list popup. This example just prints the voltage level.

```python

map_widget = NetworkMapWidget(network)
map_widget.on_selectvl(lambda event : print_infos('Selected VL : ' + event.selected_vl))
```
Binary file not shown.
67 changes: 67 additions & 0 deletions examples/data/demo_geo1.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<iidm:network xmlns:iidm="http://www.powsybl.org/schema/iidm/1_12" xmlns:lp="http://www.powsybl.org/schema/iidm/ext/line_position/1_0" xmlns:sp="http://www.powsybl.org/schema/iidm/ext/substation_position/1_0" id="sim1" caseDate="2022-04-06T13:43:05.020+02:00" forecastDistance="0" sourceFormat="test" minimumValidationLevel="STEADY_STATE_HYPOTHESIS">
<iidm:substation id="P1" country="FR" tso="RTE" geographicalTags="A">
<iidm:voltageLevel id="VLGEN" nominalV="24.0" topologyKind="BUS_BREAKER">
<iidm:busBreakerTopology>
<iidm:bus id="NGEN"/>
</iidm:busBreakerTopology>
<iidm:generator id="GEN" energySource="OTHER" minP="-9999.99" maxP="9999.99" voltageRegulatorOn="true" targetP="607.0" targetV="24.5" targetQ="301.0" bus="NGEN" connectableBus="NGEN">
<iidm:minMaxReactiveLimits minQ="-9999.99" maxQ="9999.99"/>
</iidm:generator>
</iidm:voltageLevel>
<iidm:voltageLevel id="VLHV1" nominalV="380.0" topologyKind="BUS_BREAKER">
<iidm:busBreakerTopology>
<iidm:bus id="NHV1"/>
</iidm:busBreakerTopology>
</iidm:voltageLevel>
<iidm:twoWindingsTransformer id="NGEN_NHV1" r="0.26658461538461536" x="11.104492831516762" g="0.0" b="0.0" ratedU1="24.0" ratedU2="400.0" bus1="NGEN" connectableBus1="NGEN" voltageLevelId1="VLGEN" bus2="NHV1" connectableBus2="NHV1" voltageLevelId2="VLHV1"/>
</iidm:substation>
<iidm:substation id="P2" country="FR" tso="RTE" geographicalTags="B">
<iidm:voltageLevel id="VLHV2" nominalV="380.0" topologyKind="BUS_BREAKER">
<iidm:busBreakerTopology>
<iidm:bus id="NHV2"/>
</iidm:busBreakerTopology>
</iidm:voltageLevel>
<iidm:voltageLevel id="VLLOAD" nominalV="150.0" topologyKind="BUS_BREAKER">
<iidm:busBreakerTopology>
<iidm:bus id="NLOAD"/>
</iidm:busBreakerTopology>
<iidm:load id="LOAD" loadType="UNDEFINED" p0="600.0" q0="200.0" bus="NLOAD" connectableBus="NLOAD"/>
</iidm:voltageLevel>
<iidm:twoWindingsTransformer id="NHV2_NLOAD" r="0.04724999999999999" x="4.049724365620455" g="0.0" b="0.0" ratedU1="400.0" ratedU2="158.0" bus1="NHV2" connectableBus1="NHV2" voltageLevelId1="VLHV2" bus2="NLOAD" connectableBus2="NLOAD" voltageLevelId2="VLLOAD">
<iidm:ratioTapChanger lowTapPosition="0" tapPosition="1" targetDeadband="0.0" loadTapChangingCapabilities="true" regulating="true" regulationMode="VOLTAGE" regulationValue="158.0">
<iidm:terminalRef id="NHV2_NLOAD" side="TWO"/>
<iidm:step r="0.0" x="0.0" g="0.0" b="0.0" rho="0.8505666905244191"/>
<iidm:step r="0.0" x="0.0" g="0.0" b="0.0" rho="1.0006666666666666"/>
<iidm:step r="0.0" x="0.0" g="0.0" b="0.0" rho="1.150766642808914"/>
</iidm:ratioTapChanger>
</iidm:twoWindingsTransformer>
</iidm:substation>
<iidm:line id="NHV1_NHV2_1" r="3.0" x="33.0" g1="0.0" b1="1.93E-4" g2="0.0" b2="1.93E-4" bus1="NHV1" connectableBus1="NHV1" voltageLevelId1="VLHV1" bus2="NHV2" connectableBus2="NHV2" voltageLevelId2="VLHV2"/>
<iidm:line id="NHV1_NHV2_2" r="3.0" x="33.0" g1="0.0" b1="1.93E-4" g2="0.0" b2="1.93E-4" bus1="NHV1" connectableBus1="NHV1" voltageLevelId1="VLHV1" bus2="NHV2" connectableBus2="NHV2" voltageLevelId2="VLHV2"/>
<iidm:extension id="P1">
<sp:substationPosition>
<sp:coordinate longitude="2.0" latitude="48.0"/>
</sp:substationPosition>
</iidm:extension>
<iidm:extension id="P2">
<sp:substationPosition>
<sp:coordinate longitude="2.1" latitude="48.1"/>
</sp:substationPosition>
</iidm:extension>

<iidm:extension id="NHV1_NHV2_1">
<lp:linePosition>
<sp:coordinate longitude="2.0" latitude="48.0"/>
<sp:coordinate longitude="2.1" latitude="48.1"/>
</lp:linePosition>
</iidm:extension>

<iidm:extension id="NHV1_NHV2_2">
<lp:linePosition>
<sp:coordinate longitude="2.0" latitude="48.0"/>
<sp:coordinate longitude="2.1" latitude="48.1"/>
</lp:linePosition>
</iidm:extension>

</iidm:network>
140 changes: 140 additions & 0 deletions examples/demo_mapviewer_features.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import pypowsybl.network as pn\n",
"import pypowsybl.loadflow as lf\n",
"import ipywidgets as widgets"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from pypowsybl_jupyter import NetworkMapWidget"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Example 1\n",
"# load a CGMES file containing a GL profile (Graphical Layout) and run a LF\n",
"network1 = pn.load('./data/MicroGridTestConfiguration_T4_BE_BB_Complete_v2.zip', {'iidm.import.cgmes.post-processors': 'cgmesGLImport'})\n",
"network_lf_results=lf.run_ac(network1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#declare a text place where events data will be displayed\n",
"out_events = widgets.Output()\n",
"def print_infos(data): \n",
" with out_events:\n",
" print(data)\n",
"print_infos('Events log:')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#create a map widget for the network and activate a callback on the selected VL event\n",
"map_widget1 = NetworkMapWidget(network1)\n",
"map_widget1.on_selectvl(lambda event : print_infos('Selected VL : ' + event.selected_vl))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#finally, display the widget\n",
"widgets.HBox([map_widget1, out_events])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Example 2\n",
"# load a network that includes geographical data extensions, run a LF and display the network with the NetworkMap widget"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"network2=pn.load('./data/demo_geo1.xml')\n",
"lf_results2=lf.run_ac(network2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"network_map2=NetworkMapWidget(network2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"display(network_map2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# center the map on a specific substation\n",
"network_map2.center_on_substation('P1')"
]
}
],
"metadata": {
"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.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
23 changes: 23 additions & 0 deletions examples/demo_network_explorer.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"metadata": {},
"outputs": [],
"source": [
"#activate the network explorer. Note that, since the network doesn't include geo data, the Metwork map tab is empty.\n",
"network_explorer(network, depth=4)"
]
},
Expand All @@ -41,6 +42,28 @@
"#uses NadParameters and SldParameters to customize the diagrams\n",
"network_explorer(network, depth=0, sld_parameters=pn.SldParameters(nodes_infos=True), nad_parameters=pn.NadParameters(edge_info_along_edge=True))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ae309429-9898-46b9-831f-df285a08ad5a",
"metadata": {},
"outputs": [],
"source": [
"#load a network containig geo data, imported from a CGMES file containing a GL profile (Graphical Layout)\n",
"network_microgrid = pn.load('./data/MicroGridTestConfiguration_T4_BE_BB_Complete_v2.zip', {'iidm.import.cgmes.post-processors': 'cgmesGLImport'})"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bf3c4d2f-cc7a-463b-b879-c2ac392888a0",
"metadata": {},
"outputs": [],
"source": [
"#explore the network. Apply a filter in the map to show the two top tier nominal voltage (filter can be changed, later, through the widget)\n",
"network_explorer(network_microgrid, nominal_voltages_top_tiers_filter=2)"
]
}
],
"metadata": {
Expand Down
8 changes: 8 additions & 0 deletions js/networkmapwidget.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.network-map-viewer-widget {
border: 2px solid lightgrey;
display: inline-block;
}

.maplibregl-ctrl-bottom-left {
display: none;
}
Loading

0 comments on commit f5cbcb4

Please sign in to comment.