Skip to content

Commit

Permalink
adds a function parameter to the explorer, to filter the voltage leve…
Browse files Browse the repository at this point in the history
…ls list using some custom logic

Signed-off-by: Christian Biasuzzi <christian.biasuzzi@soft.it>
  • Loading branch information
CBiasuzzi committed Aug 30, 2024
1 parent f764dba commit ce273a2
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 6 deletions.
117 changes: 117 additions & 0 deletions examples/demo_network_explorer_filter_function.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "f42abf42-4718-4f92-a542-68ae289906a6",
"metadata": {},
"outputs": [],
"source": [
"import pypowsybl.network as pn\n",
"from pypowsybl_jupyter import network_explorer"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ece1d9b1-31b4-4b43-8e2c-42773d7ffbeb",
"metadata": {},
"outputs": [],
"source": [
"#Define a ComponentType enum for a Network, and a filter function that returns the set of the network VL's ids, \n",
"#for all the VLs that include a component of type c_type"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "20558132-2382-49e9-ac8e-c5b7afd0d139",
"metadata": {},
"outputs": [],
"source": [
"from enum import Enum\n",
"\n",
"class ComponentType(Enum):\n",
" LINE = 'LINE'\n",
" TWT = 'TWT'\n",
" SVC = 'SVC' \n",
" GENERATOR = 'GENERATOR'\n",
" BATTERY = 'BATTERY'\n",
"\n",
"def filter_vls_by_included_component_type(network: pn.Network, c_type:ComponentType):\n",
" if c_type == ComponentType.LINE:\n",
" df = network.get_lines()[['voltage_level1_id', 'voltage_level2_id']]\n",
" vls = set(df['voltage_level1_id']).union(set(df['voltage_level2_id']))\n",
" elif c_type == ComponentType.TWT:\n",
" df = network.get_2_windings_transformers()[['voltage_level1_id', 'voltage_level2_id']]\n",
" vls = set(df['voltage_level1_id']).union(set(df['voltage_level2_id']))\n",
" elif c_type == ComponentType.GENERATOR:\n",
" df = network.get_generators()[['voltage_level_id']]\n",
" vls = set(df['voltage_level_id']) \n",
" elif c_type == ComponentType.SVC:\n",
" df = network.get_static_var_compensators()[['voltage_level_id']]\n",
" vls = set(df['voltage_level_id']) \n",
" elif c_type == ComponentType.BATTERY:\n",
" df = network.get_batteries()[['voltage_level_id']]\n",
" vls = set(df['voltage_level_id']) \n",
" \n",
" if len(vls) == 0: \n",
" raise ValueError(f'the network does not contain any voltage level that includse a {c_type.name}')\n",
"\n",
" return vls"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5ca2e7af-7d2a-4169-b71d-57cf3f8980a4",
"metadata": {},
"outputs": [],
"source": [
"# Creates a network, then opens an explorer filtering the VL by component type"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ce646543-5d2d-4933-8106-dfb7a281124e",
"metadata": {},
"outputs": [],
"source": [
"four_substations_network = pn.create_four_substations_node_breaker_network()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6bb2f0a1-97e4-4cf5-975b-7e1651c830bb",
"metadata": {},
"outputs": [],
"source": [
"network_explorer(four_substations_network,\n",
" filter_vls_function = lambda network: filter_vls_by_included_component_type(network, ComponentType.SVC))"
]
}
],
"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": 5
}
7 changes: 5 additions & 2 deletions src/pypowsybl_jupyter/networkexplorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#

from pypowsybl.network import Network, NadParameters, SldParameters
from typing import Callable, Set
from .nadwidget import display_nad, update_nad
from .sldwidget import display_sld, update_sld
from .selectcontext import SelectContext
Expand All @@ -14,7 +15,8 @@

def 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):
nad_parameters: NadParameters = None, sld_parameters: SldParameters = None,
filter_vls_function: Callable[[Network], Set[str]] = None):
"""
Creates a combined NAD and SLD explorer widget for the network. Diagrams are displayed on two different tabs.
Expand All @@ -27,6 +29,7 @@ def network_explorer(network: Network, vl_id : str = None, use_name:bool = True,
high_nominal_voltage_bound: high bound to filter voltage level according to nominal voltage
nad_parameters: layout properties to adjust the svg rendering for the NAD
sld_parameters: layout properties to adjust the svg rendering for the SLD
filter_vls_function: filter the voltage levels list, using some custom logic. The parameter function must return a set of VL ids
Examples:
Expand All @@ -35,7 +38,7 @@ def network_explorer(network: Network, vl_id : str = None, use_name:bool = True,
network_explorer(pp.network.create_eurostag_tutorial_example1_network())
"""

sel_ctx=SelectContext(network, vl_id, use_name, history_max_length = 10)
sel_ctx=SelectContext(network, vl_id, use_name, history_max_length = 10, filter_vls_function = filter_vls_function)

nad_widget=None
sld_widget=None
Expand Down
26 changes: 22 additions & 4 deletions src/pypowsybl_jupyter/selectcontext.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
import pandas as pd
from collections import deque
from pypowsybl.network import Network
from typing import Callable, Set

class SelectContext:

def __init__(self, network:Network = None, vl_id : str = None, use_name:bool = True, history_max_length:int = -1):
def __init__(self, network:Network = None, vl_id : str = None, use_name:bool = True, history_max_length:int = -1, filter_vls_function: Callable[[Network], Set[str]] = None):
self.network = network
self.use_name = use_name
self.display_attribute = 'name' if use_name else 'id'
Expand All @@ -20,13 +21,24 @@ def __init__(self, network:Network = None, vl_id : str = None, use_name:bool = T
self.vls['name'] = self.vls['name'].replace('', pd.NA).fillna(self.vls.index.to_series().astype(str))
self.vls['id'] = self.vls.index

if self.vls.empty:
raise ValueError(f'the network does not contain any voltage level.')

self.filter_vls_function = filter_vls_function

self.vls = self.vls.sort_values(by=self.display_attribute) if use_name else self.vls.sort_index()

self.apply_filter(None)

self.history = deque(maxlen=None if history_max_length == -1 else history_max_length)

self.set_selected(self.vls.index[0] if vl_id is None else vl_id)
self.set_selected(self.vls_filtered.index[0] if vl_id is None else vl_id)

def filter_vls(self, filter_function: Callable[[Network], Set[str]]) -> pd.DataFrame:
vls_df = self.get_vls()
filtered_vls_ids = filter_function(self.network)
filtered_vls = vls_df[vls_df['id'].isin(filtered_vls_ids)]
return filtered_vls

def get_vls(self):
return self.vls
Expand All @@ -42,11 +54,17 @@ def get_selected(self):
return self.selected_vl

def apply_filter(self, sfilter, search_attribute = None):
if self.filter_vls_function is not None:
funcfiltered=self.filter_vls(self.filter_vls_function)
else:
funcfiltered=self.vls

if sfilter is not None and sfilter != '':
search_by = self.display_attribute if search_attribute is None else search_attribute
self.vls_filtered = self.vls[self.vls[search_by].str.contains(sfilter, case=False, na=False, regex=False)]
self.vls_filtered = funcfiltered[funcfiltered[search_by].str.contains(sfilter, case=False, na=False, regex=False)]
else:
self.vls_filtered = self.vls
self.vls_filtered = funcfiltered


def is_selected_in_filtered_vls(self):
return self.selected_vl in self.vls_filtered.index
Expand Down

0 comments on commit ce273a2

Please sign in to comment.