Skip to content

Commit

Permalink
NAD lazy processing for the explorer (#28)
Browse files Browse the repository at this point in the history
* only computes NAD diagram data when the NAD tab is the currently displayed tab
* displays an animated bar during the computation
* mapviewer widget: adds a set_enable_callbacks function to disable/enable sending of events, from the js to python
* removes useless js code
* update docs

Signed-off-by: Christian Biasuzzi <christian.biasuzzi@soft.it>
  • Loading branch information
CBiasuzzi authored Nov 6, 2024
1 parent 24483ab commit 9017d53
Show file tree
Hide file tree
Showing 10 changed files with 192 additions and 109 deletions.
14 changes: 8 additions & 6 deletions docs/user_guide/nad_widget.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,24 @@ update_nad(nad, network.get_network_area_diagram(voltage_level_ids=vlid, depth=0
## Widget API

```python
display_nad(svg, invalid_lf: bool = False, enable_callbacks: bool = False) -> NadWidget
display_nad(svg, invalid_lf: bool = False, enable_callbacks: bool = False, grayout: bool = False) -> NadWidget
```

- svg: the input SVG, as str or class providing an svg and metadata representation
- invalid_lf: When True the opacity style for some of the displayed info's (e.g., active and reactive power) is decreased, making them barely visible in the diagram.
- enable_callbacks: if true, enable the callbacks for selecting nodes (through a shift+click on a node) and moving nodes
- invalid_lf: when True the opacity style for some of the displayed info's (e.g., active and reactive power) is decreased, making them barely visible in the diagram.
- enable_callbacks: if True, enable the callbacks for selecting nodes (through a shift+click on a node) and moving nodes.
- grayout: if True, changes the diagram elements' color to gray.


```python
update_nad(nadwidget, svg, invalid_lf: bool = False, enable_callbacks: bool = False)
update_nad(nadwidget, svg, invalid_lf: bool = False, enable_callbacks: bool = False, grayout: bool = False)
```

- nadwidget: the existing widget to update
- svg: the input NAD's SVG
- invalid_lf: When True the opacity style for some of the displayed info's (e.g., active and reactive power) is decreased, making them barely visible in the diagram.
- enable_callbacks: if true, enable the callbacks for selecting nodes (through a SHIFT+CLICK on a node) and moving nodes
- invalid_lf: when True the opacity style for some of the displayed info's (e.g., active and reactive power) is decreased, making them barely visible in the diagram.
- enable_callbacks: if True, enable the callbacks for selecting nodes (through a SHIFT+CLICK on a node) and moving nodes.
- grayout: if True, changes the diagram elements' color to gray.

## Customize widget's interactions
By default, only the pan and zoom interactions with the diagram are active.
Expand Down
16 changes: 8 additions & 8 deletions docs/user_guide/sld_widget.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,20 @@ update_sld(sld, network.get_single_line_diagram(vl1))
display_sld(svg, enable_callbacks: bool = False, invalid_lf: bool = False) -> SldWidget:
```

- svg: the input SVG, as str or class providing an svg and metadata representation
- enable_callbacks: if true, enable the callbacks for navigation arrows, feeders and switches
- invalid_lf: When True the opacity style for some of the displayed info's (e.g., active and reactive power) is decreased, making them barely visible in the diagram.
- svg: the input SVG, as str or class providing an svg and metadata representation.
- enable_callbacks: if true, enable the callbacks for navigation arrows, feeders and switches.
- invalid_lf: when True the opacity style for some of the displayed info's (e.g., active and reactive power) is decreased, making them barely visible in the diagram.


```python
update_sld(sldwidget, svg, keep_viewbox: bool = False, enable_callbacks: bool = False, invalid_lf: bool = False)
```

- sldwidget: the existing widget to update
- svg: the input NAD's SVG
- keep_viewbox: if True, keeps the current pan and zoom after the update
- enable_callbacks: if true, enable the callbacks for navigation arrows, feeders and switches
- invalid_lf: When True the opacity style for some of the displayed info's (e.g., active and reactive power) is decreased, making them barely visible in the diagram.
- sldwidget: the existing widget to update.
- svg: the input NAD's SVG.
- keep_viewbox: if True, keeps the current pan and zoom after the update.
- enable_callbacks: if True, enable the callbacks for navigation arrows, feeders and switches.
- invalid_lf: when True the opacity style for some of the displayed info's (e.g., active and reactive power) is decreased, making them barely visible in the diagram.


## Customize widget's interactions
Expand Down
7 changes: 7 additions & 0 deletions js/nadwidget.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,10 @@
.invalid-lf .nad-edge-infos {
opacity: 0.2;
}

.grayout :is(.nad-vl-nodes *, .nad-branch-edges *, .nad-text-edges *, .nad-text-nodes *, .nad-vl-nodes .nad-overvoltage *, .nad-vl-nodes .nad-undervoltage *, .nad-branch-edges .nad-overload .nad-edge-path *) {
opacity: 0.9;
--nad-vl-color: #7d7f7c;
stroke: #7d7f7c;
animation-play-state: paused;
}
3 changes: 3 additions & 0 deletions js/nadwidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,16 @@ function render({ model, el }: RenderProps<NadWidgetModel>) {
const diagram_data = model.get('diagram_data');
const svg_data = diagram_data['svg_data']; //svg content
const is_invalid_lf = diagram_data['invalid_lf'];
const is_grayout = diagram_data['grayout'];
const is_enabled_callbacks = diagram_data['enable_callbacks'];

const el_div = document.createElement('div');
el_div.classList.add('svg-nad-viewer-widget');

el_div.classList.toggle('invalid-lf', is_invalid_lf);

el_div.classList.toggle('grayout', is_grayout);

new NetworkAreaDiagramViewer(
el_div,
svg_data,
Expand Down
58 changes: 7 additions & 51 deletions js/networkmapwidget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,6 @@ class WidgetMapEquipments extends MapEquipments {
}
}

//called after a click (right mouse click) on an equipment (line or substation)
function showEquipmentMenu(equipment, x, y, type) {
console.log(
'# Show equipment menu: ' +
JSON.stringify(equipment) +
', type: ' +
type
);
}

const render = createRender(() => {
const networkMapRef = useRef();

Expand All @@ -123,6 +113,8 @@ const render = createRender(() => {
const [params, setParams] = useModelState('params');
const [nvls] = useModelState('nvls');

const [enable_callbacks] = useModelState('enable_callbacks');

const targetSubId = params['subId'];
const [centerOnSubId, setCenterOnSubId] = useState(
targetSubId === null ? null : { to: targetSubId }
Expand Down Expand Up @@ -156,23 +148,6 @@ const render = createRender(() => {
});
}, []);

useEffect(() => {
const handleContextmenu = (e) => {
//e.preventDefault();
e.stopPropagation();
};
networkMapRef.current.addEventListener(
'contextmenu',
handleContextmenu
);
return () => {
networkMapRef.current.removeEventListener(
'contextmenu',
handleContextmenu
);
};
}, []);

useEffect(() => {
const targetSubId = params['subId'];
if (!('centered' in params)) {
Expand All @@ -193,13 +168,14 @@ const render = createRender(() => {
}

function propagate_selectedvl_event(voltageLevelId) {
model.set('selected_vl', voltageLevelId);
model.save_changes();
model.send({ event: 'select_vl' });
if (enable_callbacks) {
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);
}
Expand Down Expand Up @@ -274,31 +250,11 @@ const render = createRender(() => {
useName={use_name}
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')
}
onTieLineMenuClick={(equipment, x, y) =>
showEquipmentMenu(equipment, x, y, 'tie-line')
}
onHvdcLineMenuClick={(equipment, x, y) =>
showEquipmentMenu(equipment, x, y, 'hvdc-line')
}
onVoltageLevelMenuClick={(equipment, x, y) => {
console.log(
`# VoltageLevel menu click: ${JSON.stringify(
equipment
)} at coordinates (${x}, ${y})`
);
}}
mapLibrary={'cartonolabel'}
mapTheme={dark_mode ? 'dark' : 'light'}
filteredNominalVoltages={filteredNominalVoltages}
Expand Down
27 changes: 27 additions & 0 deletions src/pypowsybl_jupyter/assets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# 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
#

EMPTY_SVG = '''
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 799 599" width="800" height="600" preserveAspectRatio="xMidYMid" style="display: block; background: transparent;">
<rect width="800" height="600" fill="lightgrey"/>
</svg>
'''

PROGRESS_BAR_SVG= '''
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 250 30" width="250" height="30" preserveAspectRatio="xMidYMid" style="display: block; background: transparent;">
<rect x="0" y="10" width="250" height="10" rx="5" ry="5" fill="#e0e0e0"/>
<rect x="0" y="10" width="50" height="10" rx="5" ry="5" fill="#ffb259">
<animate attributeName="x" values="0;200;0" dur="2s" repeatCount="indefinite"/>
</rect>
</svg>
'''

PROGRESS_EMPTY_SVG = '''
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 250 30" width="250" height="30" preserveAspectRatio="xMidYMid" style="display: block; background: transparent;">
<rect width="250" height="30" fill="none" stroke="none"/>
</svg>
'''
18 changes: 10 additions & 8 deletions src/pypowsybl_jupyter/nadwidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,15 @@ def _get_svg_string(svg) -> str:
else:
raise ValueError('svg argument should be a string or provide a _repr_svg_ method.')

def display_nad(svg, invalid_lf: bool = False, enable_callbacks: bool = False) -> NadWidget:
def display_nad(svg, invalid_lf: bool = False, enable_callbacks: bool = False, grayout: bool = False) -> NadWidget:
"""
Displays a NAD's SVG with support for panning and zooming.
Args:
svg: the input SVG, as str or class providing an svg and metadata representation
invalid_lf: When True the opacity style for some of the displayed info's (e.g., active and reactive power) is decreased, making them barely visible in the diagram.
enable_callbacks: if true, enable the callbacks for moving and selecting nodes in the diagram.
invalid_lf: when True the opacity style for some of the displayed info's (e.g., active and reactive power) is decreased, making them barely visible in the diagram.
enable_callbacks: if True, enable the callbacks for moving and selecting nodes in the diagram.
grayout: if True, changes the diagram elements' color to gray.
Returns:
A jupyter widget allowing to zoom and pan the SVG.
Expand All @@ -89,17 +90,18 @@ def display_nad(svg, invalid_lf: bool = False, enable_callbacks: bool = False) -
display_nad(network.get_network_area_diagram())
"""
return NadWidget(diagram_data= {"svg_data": _get_svg_string(svg), "invalid_lf": invalid_lf, "enable_callbacks": enable_callbacks})
return NadWidget(diagram_data= {"svg_data": _get_svg_string(svg), "invalid_lf": invalid_lf, "enable_callbacks": enable_callbacks, "grayout": grayout})

def update_nad(nadwidget, svg, invalid_lf: bool = False, enable_callbacks: bool = False):
def update_nad(nadwidget, svg, invalid_lf: bool = False, enable_callbacks: bool = False, grayout: bool = False):
"""
Updates an existing NAD widget with a new SVG content
Args:
nadwidget: the existing widget to update
svg: the input NAD's SVG
invalid_lf: When True the opacity style for some of the displayed info's (e.g., active and reactive power) is decreased, making them barely visible in the diagram.
enable_callbacks: if true, enable the callbacks for moving and selecting nodes in the diagram.
invalid_lf: when True the opacity style for some of the displayed info's (e.g., active and reactive power) is decreased, making them barely visible in the diagram.
enable_callbacks: if True, enable the callbacks for moving and selecting nodes in the diagram.
grayout: if True, changes the diagram elements' color to gray.
Examples:
Expand All @@ -109,4 +111,4 @@ def update_nad(nadwidget, svg, invalid_lf: bool = False, enable_callbacks: bool
"""

svg_value=_get_svg_string(svg)
nadwidget.diagram_data= {"svg_data": svg_value, "invalid_lf": invalid_lf, "enable_callbacks": enable_callbacks}
nadwidget.diagram_data= {"svg_data": svg_value, "invalid_lf": invalid_lf, "enable_callbacks": enable_callbacks, "grayout": grayout}
Loading

0 comments on commit 9017d53

Please sign in to comment.