diff --git a/docs/user_guide/nad_widget.md b/docs/user_guide/nad_widget.md index 902cdca..54ee89f 100644 --- a/docs/user_guide/nad_widget.md +++ b/docs/user_guide/nad_widget.md @@ -37,7 +37,7 @@ display_nad(svg, invalid_lf: bool = False, enable_callbacks: bool = False, grayo - 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. +- enable_callbacks: if True, enable the callbacks for selecting nodes (through a shift+click on a node) and moving nodes. Please note that this feature is working with versions of PyPowSyBl equal or greater than v1.8.1. - grayout: if True, changes the diagram elements' color to gray. @@ -48,7 +48,7 @@ update_nad(nadwidget, svg, invalid_lf: bool = False, enable_callbacks: bool = Fa - 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. +- enable_callbacks: if True, enable the callbacks for selecting nodes (through a SHIFT+CLICK on a node) and moving nodes. Please note that this feature is working with versions of PyPowSyBl equal or greater than v1.8.1. - grayout: if True, changes the diagram elements' color to gray. ## Customize widget's interactions @@ -64,6 +64,8 @@ Use these widget's methods to register a callback on a specific event: The [network explorer widget](/user_guide/network_explorer.md) demonstrates the approach. +Please note that the callbacks works with versions of PyPowSyBl equal or greater than v1.8.1. + Example: the code below activates a callback when a node is selected (through SHIFT+CLICK) in the widget (it prints the selected node's ID to the log). ```python diff --git a/docs/user_guide/network_explorer.md b/docs/user_guide/network_explorer.md index 8feec1d..245fccd 100644 --- a/docs/user_guide/network_explorer.md +++ b/docs/user_guide/network_explorer.md @@ -23,7 +23,7 @@ The selected voltage level is the displayed NAD's center. A 'depth' slider controls the size of the sub network. -Selecting a VL's node (through SHIFT+CLICK) will activate the SLD panel on the corresponding voltage level. +Selecting a VL's node (through SHIFT+CLICK) will activate the SLD panel on the corresponding voltage level. Please note that this feature is working with versions of PyPowSyBl equal or greater than v1.8.1. ## Single Line tab @@ -38,6 +38,8 @@ Switches can also be clicked, causing their status in the network to change; Ple ![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. +Please note that substation's and line's IIDM extensions are only available in PyPowSyBl starting from v1.5.0; With earlier versions of PyPowSyBl the map would be empty, too. + 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) diff --git a/docs/user_guide/network_map_widget.md b/docs/user_guide/network_map_widget.md index 6dd0157..acd1d59 100644 --- a/docs/user_guide/network_map_widget.md +++ b/docs/user_guide/network_map_widget.md @@ -6,6 +6,9 @@ The widget allows you to pan and zoom the map. A filter on the network's nominal The following code, to be run in a notebook, first creates a network, then displays the Network map widget on it. +Please note that substation's and line's IIDM extensions are only available in PyPowSyBl starting from v1.5.0; With earlier versions of PyPowSyBl the map would be empty. + + ```python import pypowsybl.network as pn from pypowsybl_jupyter import NetworkMapWidget diff --git a/js/nadwidget.ts b/js/nadwidget.ts index 220f02b..c9a55b2 100644 --- a/js/nadwidget.ts +++ b/js/nadwidget.ts @@ -8,7 +8,7 @@ import type { RenderProps } from '@anywidget/types'; import './nadwidget.css'; -import { NetworkAreaDiagramViewer } from '@powsybl/diagram-viewer'; +import { NetworkAreaDiagramViewer } from '@powsybl/network-viewer'; interface NadWidgetModel { diagram_data: any; @@ -79,7 +79,8 @@ function render({ model, el }: RenderProps) { function render_diagram(model: any): any { const diagram_data = model.get('diagram_data'); - const svg_data = diagram_data['svg_data']; //svg content + const svg_data = diagram_data['svg_data']; + const metadata = diagram_data['metadata']; const is_invalid_lf = diagram_data['invalid_lf']; const is_grayout = diagram_data['grayout']; const is_enabled_callbacks = diagram_data['enable_callbacks']; @@ -94,6 +95,7 @@ function render({ model, el }: RenderProps) { new NetworkAreaDiagramViewer( el_div, svg_data, + metadata ? JSON.parse(metadata) : null, 800, 600, 800, @@ -103,6 +105,7 @@ function render({ model, el }: RenderProps) { handleSelectNode, is_enabled_callbacks, false, + null, null ); diff --git a/js/networkmapwidget.jsx b/js/networkmapwidget.jsx index 1a752bd..3f71793 100644 --- a/js/networkmapwidget.jsx +++ b/js/networkmapwidget.jsx @@ -9,7 +9,7 @@ import React, { useEffect, useRef, useState, useCallback } from 'react'; import { createRender, useModelState, useModel } from '@anywidget/react'; -import { NetworkMap, GeoData, MapEquipments } from '@powsybl/diagram-viewer'; +import { NetworkMap, GeoData, MapEquipments } from '@powsybl/network-viewer'; import VoltageLevelChoice from './voltage-level-choice'; import NominalVoltageFilter from './nominal-voltage-filter'; diff --git a/js/sldwidget.ts b/js/sldwidget.ts index a3cfe26..3149586 100644 --- a/js/sldwidget.ts +++ b/js/sldwidget.ts @@ -7,7 +7,7 @@ import type { RenderProps, Initialize } from '@anywidget/types'; -import { SingleLineDiagramViewer } from '@powsybl/diagram-viewer'; +import { SingleLineDiagramViewer } from '@powsybl/network-viewer'; import './sldwidget.css'; diff --git a/package-lock.json b/package-lock.json index aa2e06a..d3d99a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.0", "license": "MPL-2.0", "dependencies": { - "@powsybl/diagram-viewer": "0.5.5" + "@powsybl/network-viewer": "1.0.0" }, "devDependencies": { "@anywidget/react": "^0.0.7", @@ -2157,10 +2157,10 @@ "url": "https://opencollective.com/popperjs" } }, - "node_modules/@powsybl/diagram-viewer": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/@powsybl/diagram-viewer/-/diagram-viewer-0.5.5.tgz", - "integrity": "sha512-8V3nTOMIjjlRAk3S35v7ifqFmW315geUvt9v1fNNhatSR3FwoMEGe1fSDTORzH+Wf11i7D4inXo2dYBlGmdSRw==", + "node_modules/@powsybl/network-viewer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@powsybl/network-viewer/-/network-viewer-1.0.0.tgz", + "integrity": "sha512-BIDj4uJXqvS0wZkdeSZ63/CxbckPlanZlCe2/0F5OBhiT1iFHIqjJXdCCF2th3/wMFyIF2wwWZRPb5VEg66gHg==", "dependencies": { "@mapbox/mapbox-gl-draw": "^1.4.3", "@svgdotjs/svg.js": "^3.2.0", diff --git a/package.json b/package.json index f68ef2e..fda8ca4 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "lint": "eslint . --ext js,ts,jsx --max-warnings 0" }, "dependencies": { - "@powsybl/diagram-viewer": "0.5.5" + "@powsybl/network-viewer": "1.0.0" }, "devDependencies": { "@anywidget/types": "^0.1.6", diff --git a/pyproject.toml b/pyproject.toml index 1ee6da7..1b1082d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ classifiers = [ ] dependencies = [ "anywidget", - "pypowsybl>=1.2.0", + "pypowsybl>=1.3.0", ] [project.optional-dependencies] diff --git a/src/pypowsybl_jupyter/nadwidget.py b/src/pypowsybl_jupyter/nadwidget.py index 8b3b2f6..c9b71a7 100644 --- a/src/pypowsybl_jupyter/nadwidget.py +++ b/src/pypowsybl_jupyter/nadwidget.py @@ -18,6 +18,8 @@ CallbackDispatcher ) +from .util import _get_svg_string, _get_svg_metadata + class NadWidget(anywidget.AnyWidget): _esm = pathlib.Path(__file__).parent / "static" / "nadwidget.js" _css = pathlib.Path(__file__).parent / "static" / "nadwidget.css" @@ -63,14 +65,6 @@ def on_move_text_node_msg(self): def on_move_text_node(self, callback, remove=False): self._on_move_text_node_handler.register_callback(callback, remove=remove) -def _get_svg_string(svg) -> str: - if isinstance(svg, str): - return svg - elif hasattr(svg, '_repr_svg_'): - return svg._repr_svg_() - 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, grayout: bool = False) -> NadWidget: """ Displays a NAD's SVG with support for panning and zooming. @@ -78,7 +72,7 @@ def display_nad(svg, invalid_lf: bool = False, enable_callbacks: bool = False, g 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. + enable_callbacks: if True, enable the callbacks for moving and selecting nodes in the diagram. Please note that this feature is working with versions of PyPowSyBl equal or greater than v1.8.1. grayout: if True, changes the diagram elements' color to gray. Returns: @@ -89,8 +83,10 @@ def display_nad(svg, invalid_lf: bool = False, enable_callbacks: bool = False, g .. code-block:: python 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, "grayout": grayout}) + """ + svg_value=_get_svg_string(svg) + svg_metadata = "" if not enable_callbacks else _get_svg_metadata(svg) + return NadWidget(diagram_data= {"svg_data": svg_value, "metadata": svg_metadata, "invalid_lf": invalid_lf, "enable_callbacks": enable_callbacks, "grayout": grayout}) def update_nad(nadwidget, svg, invalid_lf: bool = False, enable_callbacks: bool = False, grayout: bool = False): """ @@ -100,7 +96,7 @@ def update_nad(nadwidget, svg, invalid_lf: bool = False, enable_callbacks: bool 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. + enable_callbacks: if True, enable the callbacks for moving and selecting nodes in the diagram. Please note that this feature is working with versions of PyPowSyBl equal or greater than v1.8.1. grayout: if True, changes the diagram elements' color to gray. Examples: @@ -111,4 +107,5 @@ 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, "grayout": grayout} + svg_metadata = "" if not enable_callbacks else _get_svg_metadata(svg) + nadwidget.diagram_data= {"svg_data": svg_value, "metadata": svg_metadata, "invalid_lf": invalid_lf, "enable_callbacks": enable_callbacks, "grayout": grayout} diff --git a/src/pypowsybl_jupyter/networkmapwidget.py b/src/pypowsybl_jupyter/networkmapwidget.py index a31d6b2..e5cebcb 100644 --- a/src/pypowsybl_jupyter/networkmapwidget.py +++ b/src/pypowsybl_jupyter/networkmapwidget.py @@ -18,7 +18,7 @@ import pandas as pd -from pypowsybl.network import Network +from pypowsybl.network import Network, get_extensions_names class NetworkMapWidget(anywidget.AnyWidget): """ @@ -164,7 +164,8 @@ def extract_map_data(self, network, display_lines, use_line_geodata): sub_vls = dict() subs_ids = set() - subs_positions_df = network.get_extensions('substationPosition') + # substationPosition extension is available only in PyPowSyBl starting from v1.5.0 + subs_positions_df = pd.DataFrame() if 'substationPosition' not in get_extensions_names() else network.get_extensions('substationPosition') if not subs_positions_df.empty: subs_df = network.get_substations() diff --git a/src/pypowsybl_jupyter/sldwidget.py b/src/pypowsybl_jupyter/sldwidget.py index 89106fa..366468a 100644 --- a/src/pypowsybl_jupyter/sldwidget.py +++ b/src/pypowsybl_jupyter/sldwidget.py @@ -19,6 +19,8 @@ CallbackDispatcher ) +from .util import _get_svg_string, _get_svg_metadata + class SldWidget(anywidget.AnyWidget): _esm = pathlib.Path(__file__).parent / "static" / "sldwidget.js" _css = pathlib.Path(__file__).parent / "static" / "sldwidget.css" @@ -75,23 +77,6 @@ def on_bus_msg(self): def on_bus(self, callback, remove=False): self._on_bus_handlers.register_callback(callback, remove=remove) - -def _get_svg_string(svg) -> str: - if isinstance(svg, str): - return svg - elif hasattr(svg, '_repr_svg_'): - return svg._repr_svg_() - else: - raise ValueError('svg argument should be a string or provide a _repr_svg_ method.') - -def _get_svg_metadata(svg) -> str: - if isinstance(svg, str): - return None - elif hasattr(svg, '_metadata'): - return svg._metadata - else: - raise ValueError('svg argument provide a _metadata method.') - def display_sld(svg, enable_callbacks: bool = False, invalid_lf: bool = False) -> SldWidget: """ Displays an SLD's SVG with support for panning and zooming. diff --git a/src/pypowsybl_jupyter/util.py b/src/pypowsybl_jupyter/util.py new file mode 100644 index 0000000..b9acde7 --- /dev/null +++ b/src/pypowsybl_jupyter/util.py @@ -0,0 +1,22 @@ +# 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 +# + +def _get_svg_string(svg) -> str: + if isinstance(svg, str): + return svg + elif hasattr(svg, '_repr_svg_'): + return svg._repr_svg_() + else: + raise ValueError('svg argument should be a string or provide a _repr_svg_ method.') + +def _get_svg_metadata(svg) -> str: + if isinstance(svg, str): + return None + elif hasattr(svg, '_metadata'): + return svg._metadata + else: + raise ValueError('svg argument provide a _metadata method.')