Skip to content

Commit

Permalink
adds the VL picker and the VL nominal voltage filter to the map widge…
Browse files Browse the repository at this point in the history
…t; adds a widget callback mechanism so that it is possible to intercept picked VL from python; fixes the map demo notebook

Signed-off-by: Christian Biasuzzi <[email protected]>
  • Loading branch information
CBiasuzzi committed Jun 16, 2024
1 parent c915f67 commit 4b5e898
Show file tree
Hide file tree
Showing 5 changed files with 457 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"outputs": [],
"source": [
"import pypowsybl.network as pn\n",
"import pypowsybl.loadflow as lf"
"import pypowsybl.loadflow as lf\n",
"import ipywidgets as widgets"
]
},
{
Expand All @@ -26,7 +27,9 @@
"outputs": [],
"source": [
"# Example 1\n",
"# load a CGMES file containing a GL profile (Graphical Layout) and display it with the NetworkMap widget"
"# 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)"
]
},
{
Expand All @@ -35,7 +38,12 @@
"metadata": {},
"outputs": [],
"source": [
"network2 = pn.load('./data/MicroGridTestConfiguration_T4_BE_BB_Complete_v2.zip', {'iidm.import.cgmes.post-processors': 'cgmesGLImport'})"
"#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:')"
]
},
{
Expand All @@ -44,7 +52,9 @@
"metadata": {},
"outputs": [],
"source": [
"network2_lf_results=lf.run_ac(network2, parameters=lf.Parameters(distributed_slack=False))"
"#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))"
]
},
{
Expand All @@ -53,7 +63,8 @@
"metadata": {},
"outputs": [],
"source": [
"NetworkMapWidget(network2)"
"#finally, display the widget\n",
"widgets.HBox([map_widget1, out_events])"
]
},
{
Expand All @@ -63,7 +74,7 @@
"outputs": [],
"source": [
"# Example 2\n",
"# load a network that includes geographical data extensions and display it with the NetworkMap widget"
"# load a network that includes geographical data extensions, run a LF and display the network with the NetworkMap widget"
]
},
{
Expand All @@ -72,7 +83,8 @@
"metadata": {},
"outputs": [],
"source": [
"network=pn.load('./data/demo_geo1.xml')"
"network2=pn.load('./data/demo_geo1.xml')\n",
"lf_results2=lf.run_ac(network2, parameters=lf.Parameters(distributed_slack=False))"
]
},
{
Expand All @@ -81,7 +93,7 @@
"metadata": {},
"outputs": [],
"source": [
"lf_results=lf.run_ac(network, parameters=lf.Parameters(distributed_slack=False))"
"network_map2=NetworkMapWidget(network2)"
]
},
{
Expand All @@ -90,16 +102,7 @@
"metadata": {},
"outputs": [],
"source": [
"network_map=NetworkMapWidget(network)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"display(network_map)"
"display(network_map2)"
]
},
{
Expand All @@ -109,7 +112,7 @@
"outputs": [],
"source": [
"# center the map on a specific substation\n",
"network_map.center_on_substation('P1')"
"network_map2.center_on_substation('P1')"
]
}
],
Expand All @@ -129,7 +132,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
"version": "3.12.2"
}
},
"nbformat": 4,
Expand Down
171 changes: 125 additions & 46 deletions js/networkmapwidget.jsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
// Copyright (c) 2024, RTE (http://www.rte-france.com)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// SPDX-License-Identifier: MPL-2.0
//
import React, { useEffect, useRef, useState, useCallback } from 'react';

import React, { useEffect, useRef, useState } from 'react';

import { createRender, useModelState } from '@anywidget/react';
import { createRender, useModelState, useModel } from '@anywidget/react';
import { NetworkMap, GeoData, MapEquipments } from '@powsybl/diagram-viewer';
import VoltageLevelChoice from './voltage-level-choice';
import NominalVoltageFilter from './nominal-voltage-filter';

import './networkmapwidget.css';

import {
createTheme,
ThemeProvider,
StyledEngineProvider,
} from '@mui/material/styles';
import { Box } from '@mui/system';

const INITIAL_ZOOM = 9;
const LABELS_ZOOM_THRESHOLD = 9;
const ARROWS_ZOOM_THRESHOLD = 7;
const useName = true;

const styles = {
divNominalVoltageFilter: {
position: 'absolute',
right: '10px',
bottom: '40px',
zIndex: 0,
'&:hover': {
zIndex: 2,
},
},
};

const darkTheme = createTheme({
palette: {
mode: 'dark',
Expand Down Expand Up @@ -66,6 +75,8 @@ function showEquipmentMenu(equipment, x, y, type) {
const render = createRender(() => {
const networkMapRef = useRef();

let model = useModel();

const [spos] = useModelState('spos');
const [lpos] = useModelState('lpos');
const [smap] = useModelState('smap');
Expand Down Expand Up @@ -111,6 +122,105 @@ const render = createRender(() => {
}
}, [params]);

const [
choiceVoltageLevelsSubstationId,
setChoiceVoltageLevelsSubstationId,
] = useState(null);

const [position, setPosition] = useState([-1, -1]);

function closeChoiceVoltageLevelMenu() {
setChoiceVoltageLevelsSubstationId(null);
}

function propagate_selectedvl_event(voltageLevelId) {
model.set('selected_vl', voltageLevelId);
model.save_changes();
model.send({ event: 'select_vl' });
}

function choiceVoltageLevel(voltageLevelId) {
console.log(`# Choose Voltage Level : ${voltageLevelId}`);
closeChoiceVoltageLevelMenu();
propagate_selectedvl_event(voltageLevelId);
}

let choiceVoltageLevelsSubstation = null;
if (choiceVoltageLevelsSubstationId) {
choiceVoltageLevelsSubstation = mapEquipments?.getSubstation(
choiceVoltageLevelsSubstationId
);
}

const chooseVoltageLevelForSubstation = useCallback(
(idSubstation, x, y) => {
setChoiceVoltageLevelsSubstationId(idSubstation);
setPosition([x, y]);
},
[]
);

function renderVoltageLevelChoice() {
return (
<VoltageLevelChoice
handleClose={closeChoiceVoltageLevelMenu}
onClickHandler={choiceVoltageLevel}
substation={choiceVoltageLevelsSubstation}
position={[position[0], position[1]]}
/>
);
}

const [filteredNominalVoltages, setFilteredNominalVoltages] = useState();

function renderNominalVoltageFilter() {
return (
<Box sx={styles.divNominalVoltageFilter}>
<NominalVoltageFilter
nominalVoltages={mapEquipments.getNominalVoltages()}
filteredNominalVoltages={filteredNominalVoltages}
onChange={setFilteredNominalVoltages}
/>
</Box>
);
}

const renderMap = () => (
<NetworkMap
ref={networkMapRef}
mapEquipments={mapEquipments}
geoData={geoData}
labelsZoomThreshold={LABELS_ZOOM_THRESHOLD}
arrowsZoomThreshold={ARROWS_ZOOM_THRESHOLD}
initialZoom={INITIAL_ZOOM}
useName={useName}
centerOnSubstation={centerOnSubId}
onSubstationClick={(vlId) => {
console.log('# OpenVoltageLevel: ' + vlId);
propagate_selectedvl_event(vlId);
}}
onSubstationClickChooseVoltageLevel={
chooseVoltageLevelForSubstation
}
onSubstationMenuClick={(equipment, x, y) =>
showEquipmentMenu(equipment, x, y, 'substation')
}
onLineMenuClick={(equipment, x, y) =>
showEquipmentMenu(equipment, x, y, 'line')
}
onVoltageLevelMenuClick={(equipment, x, y) => {
console.log(
`# VoltageLevel menu click: ${JSON.stringify(
equipment
)} at coordinates (${x}, ${y})`
);
}}
mapLibrary={'cartonolabel'}
mapTheme={'dark'}
filteredNominalVoltages={filteredNominalVoltages}
/>
);

return (
<div ref={networkMapRef} className="network-map-viewer-widget">
<StyledEngineProvider injectFirst>
Expand All @@ -122,43 +232,12 @@ const render = createRender(() => {
height: 600,
}}
>
<NetworkMap
ref={networkMapRef}
mapEquipments={mapEquipments}
geoData={geoData}
labelsZoomThreshold={LABELS_ZOOM_THRESHOLD}
arrowsZoomThreshold={ARROWS_ZOOM_THRESHOLD}
initialZoom={INITIAL_ZOOM}
useName={useName}
centerOnSubstation={centerOnSubId}
onSubstationClick={(vlId) => {
console.log('# OpenVoltageLevel: ' + vlId);
}}
onSubstationClickChooseVoltageLevel={(
idSubstation,
x,
y
) =>
console.log(
`# Choose Voltage Level for substation: ${idSubstation} at coordinates (${x}, ${y})`
)
}
onSubstationMenuClick={(equipment, x, y) =>
showEquipmentMenu(equipment, x, y, 'substation')
}
onLineMenuClick={(equipment, x, y) =>
showEquipmentMenu(equipment, x, y, 'line')
}
onVoltageLevelMenuClick={(equipment, x, y) => {
console.log(
`# VoltageLevel menu click: ${JSON.stringify(
equipment
)} at coordinates (${x}, ${y})`
);
}}
mapLibrary={'cartonolabel'}
mapTheme={'dark'}
/>
{renderMap()}
{choiceVoltageLevelsSubstationId &&
renderVoltageLevelChoice()}

{mapEquipments?.substations?.length > 0 &&
renderNominalVoltageFilter()}
</div>
</ThemeProvider>
</StyledEngineProvider>
Expand Down
Loading

0 comments on commit 4b5e898

Please sign in to comment.