Skip to content

Commit ff38bb2

Browse files
committed
Add scaling, legenda and frontend layout
1 parent b19ffa8 commit ff38bb2

File tree

13 files changed

+152
-52
lines changed

13 files changed

+152
-52
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from dash import Input, Output, callback
2+
from copy import deepcopy
3+
from power_grid_model_ds._core.visualizer.layout.cytoscape_styling import DEFAULT_STYLESHEET, BRANCH_WIDTH, NODE_SIZE
4+
5+
6+
@callback(
7+
Output('cytoscape-graph', 'stylesheet', allow_duplicate=True),
8+
Input('node-scale-input', 'value'),
9+
Input('edge-scale-input', 'value'),
10+
prevent_initial_call=True
11+
)
12+
def scale_elements(node_scale, edge_scale):
13+
for scale_factor in (node_scale, edge_scale):
14+
if scale_factor is None or scale_factor <= 0:
15+
scale_factor = 1
16+
17+
new_stylesheet = deepcopy(DEFAULT_STYLESHEET)
18+
edge_style = {
19+
"selector": "edge",
20+
"style": {
21+
"width": BRANCH_WIDTH * edge_scale,
22+
},
23+
}
24+
new_stylesheet.append(edge_style)
25+
node_style = {
26+
"selector": "node",
27+
"style": {
28+
"height": NODE_SIZE * node_scale,
29+
"width": NODE_SIZE * node_scale,
30+
},
31+
}
32+
new_stylesheet.append(node_style)
33+
return new_stylesheet

src/power_grid_model_ds/_core/visualizer/callbacks/element_selection.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010

1111
@callback(
12-
Output("search-output", "children"),
12+
Output("selection-output", "children"),
1313
Input("cytoscape-graph", "selectedNodeData"),
1414
Input("cytoscape-graph", "selectedEdgeData"),
1515
)
@@ -30,4 +30,4 @@ def _to_data_table(data: dict[str, Any]):
3030
data_table = dash_table.DataTable(
3131
data=[data], columns=[{"name": key, "id": key} for key in columns], editable=False
3232
)
33-
return [header, data_table]
33+
return data_table
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from dash import callback, Output, Input
2+
3+
4+
@callback(Output('cytoscape-graph', 'layout'), Input('dropdown-update-layout', 'value'),
5+
prevent_initial_call=True)
6+
def update_layout(layout):
7+
return {'name': layout, 'animate': True}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from dash import html, dcc
2+
3+
from power_grid_model_ds._core.visualizer.layout.colors import CYTO_COLORS
4+
from power_grid_model_ds._core.visualizer.layout.cytoscape_html import LAYOUT_OPTIONS
5+
6+
NODE_SCALE_HTML = [
7+
html.I(className="fas fa-circle", style={"color": CYTO_COLORS["node"], "margin-right": "10px"}),
8+
dcc.Input(
9+
id="node-scale-input",
10+
type="number",
11+
value=1,
12+
min=0.1,
13+
step=0.03,
14+
style={"width": "75px"},
15+
),
16+
html.Span(style={"margin-right": "10px"}),
17+
18+
]
19+
20+
EDGE_SCALE_HTML = [
21+
html.I(className="fas fa-arrow-right-long", style={"color": CYTO_COLORS["line"], "margin-right": "10px"}),
22+
dcc.Input(
23+
id="edge-scale-input",
24+
type="number",
25+
value=1,
26+
min=0.1,
27+
step=0.03,
28+
style={"width": "75px"},
29+
),
30+
]
31+
32+
SCALE_INPUTS = [
33+
html.Div(
34+
NODE_SCALE_HTML + EDGE_SCALE_HTML,
35+
style={"margin": "0 20px 0 10px"},
36+
),
37+
]
38+
39+
LAYOUT_DROPDOWN_HTML = [
40+
html.Div(dcc.Dropdown(
41+
id='dropdown-update-layout',
42+
placeholder="Select layout",
43+
value="",
44+
clearable=False,
45+
options=[{'label': name.capitalize(), 'value': name} for name in LAYOUT_OPTIONS],
46+
style={"width": "200px"}),
47+
style={"margin": "0 20px 0 10px"}
48+
)]

src/power_grid_model_ds/_core/visualizer/layout/cytoscape.py renamed to src/power_grid_model_ds/_core/visualizer/layout/cytoscape_html.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
from power_grid_model_ds._core.visualizer.layout.colors import BACKGROUND_COLOR
77
from power_grid_model_ds._core.visualizer.layout.cytoscape_styling import DEFAULT_STYLESHEET
88

9-
LayoutOptions = Literal["", "random", "circle", "concentric", "grid", "cose", "breadthfirst", "preset"]
9+
LAYOUT_OPTIONS = ["random", "circle", "concentric", "grid", "cose", "breadthfirst", "preset"]
1010

1111
_CYTO_INNER_STYLE = {"width": "100%", "height": "100%", "background-color": BACKGROUND_COLOR}
12-
_CYTO_OUTER_STYLE = {"height": "75vh"}
12+
_CYTO_OUTER_STYLE = {"height": "100vh"}
1313

1414

15-
def get_cytoscape_html(layout: LayoutOptions, elements: list[dict[str, Any]]) -> html.Div:
15+
def get_cytoscape_html(layout: str, elements: list[dict[str, Any]]) -> html.Div:
1616
"""Get the Cytoscape HTML element"""
1717
return html.Div(
1818
cyto.Cytoscape(

src/power_grid_model_ds/_core/visualizer/layout/cytoscape_styling.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@
22

33
from power_grid_model_ds._core.visualizer.layout.colors import CYTO_COLORS
44

5+
NODE_SIZE = 100
6+
BRANCH_WIDTH = 10
7+
58
_BRANCH_STYLE = {
69
"selector": "edge",
710
"style": {
811
"line-color": CYTO_COLORS["line"],
912
"target-arrow-color": CYTO_COLORS["line"],
1013
"curve-style": "bezier",
1114
"target-arrow-shape": "triangle",
12-
"width": 7,
15+
"width": BRANCH_WIDTH,
1316
},
1417
}
1518
_NODE_STYLE = {
@@ -51,8 +54,8 @@
5154
"shape": "diamond",
5255
"background-color": CYTO_COLORS["substation_node"],
5356
"text-background-color": CYTO_COLORS["substation_node"],
54-
"width": 100,
55-
"height": 100,
57+
"width": NODE_SIZE * 1.2,
58+
"height": NODE_SIZE * 1.2,
5659
"color": "white",
5760
},
5861
}
Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
import dash_bootstrap_components as dbc
2-
from dash import html
2+
from dash import html, dcc
33

44
from power_grid_model_ds._core.visualizer.layout.colors import BACKGROUND_COLOR
5+
from power_grid_model_ds._core.visualizer.layout.cytoscape_config import LAYOUT_DROPDOWN_HTML, SCALE_INPUTS
56
from power_grid_model_ds._core.visualizer.layout.legenda import LEGENDA_HTML
67
from power_grid_model_ds._core.visualizer.layout.search_form import SEARCH_FORM_HTML
78

9+
_SEARCH_FORM_CARD_STYLE={"background-color": "#555555", "color": "white", "border-left": "1px solid white",
10+
"border-right": "1px solid white", "border-radius": 0}
11+
812

913
HEADER_HTML = dbc.Row(
1014
[
11-
dbc.Col(LEGENDA_HTML, className="d-flex align-items-center", style={"margin": "0 10px"}),
15+
dbc.Col(LEGENDA_HTML, className="d-flex align-items-center"),
1216
dbc.Col(
13-
dbc.Card(SEARCH_FORM_HTML, style={"background-color": "#555555", "color": "white", "border": "none", "border-radius": 0}),
17+
dbc.Card(SEARCH_FORM_HTML, style=_SEARCH_FORM_CARD_STYLE),
1418
className="d-flex justify-content-center align-items-center"
1519
),
1620
dbc.Col(
17-
# Right column - empty or for future controls
18-
html.Div(),
19-
className="d-flex justify-content-end align-items-center"
20-
),
21+
SCALE_INPUTS + LAYOUT_DROPDOWN_HTML
22+
, className="d-flex justify-content-end align-items-center"),
2123
],
2224
style={"background-color": BACKGROUND_COLOR},
23-
24-
2525
)

src/power_grid_model_ds/_core/visualizer/layout/legenda.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,34 @@
11
from dash import html
2+
import dash_bootstrap_components as dbc
23

34
from power_grid_model_ds._core.visualizer.layout.colors import CYTO_COLORS
45

5-
_TEST_SHADOW = "0 0 5px #000"
6-
7-
_NODE_ICON_STYLE = {"font-size": "2.5em", "margin": "0 10px", "color": CYTO_COLORS["node"], "text-shadow": _TEST_SHADOW}
8-
_SUBSTATION_ICON_STYLE = {"font-size": "2.5em", "margin": "0 10px", "color": CYTO_COLORS["substation_node"], "text-shadow": _TEST_SHADOW}
9-
_LINE_ICON_STYLE = {"font-size": "2.5em", "margin": "0 10px", "color": CYTO_COLORS["line"], "text-shadow": _TEST_SHADOW}
10-
_LINK_ICON_STYLE = {"font-size": "2.5em", "margin": "0 10px", "color": CYTO_COLORS["link"], "text-shadow": _TEST_SHADOW}
11-
_TRANSFORMER_ICON_STYLE = {"font-size": "2.5em", "margin": "0 10px", "color": CYTO_COLORS["transformer"], "text-shadow": _TEST_SHADOW}
12-
_OPEN_BRANCH_ICON_STYLE = {"font-size": "2.5em", "margin": "0 10px", "color": CYTO_COLORS["open_branch"], "text-shadow": _TEST_SHADOW}
6+
NODE_ICON_STYLE = {"font-size": "2.5em", "margin": "0 10px", "color": CYTO_COLORS["node"]}
7+
_SUBSTATION_ICON_STYLE = {"font-size": "2.5em", "margin": "0 10px", "color": CYTO_COLORS["substation_node"]}
8+
_LINE_ICON_STYLE = {"font-size": "2.5em", "margin": "0 10px", "color": CYTO_COLORS["line"]}
9+
_LINK_ICON_STYLE = {"font-size": "2.5em", "margin": "0 10px", "color": CYTO_COLORS["link"]}
10+
_TRANSFORMER_ICON_STYLE = {"font-size": "2.5em", "margin": "0 10px", "color": CYTO_COLORS["transformer"]}
11+
_OPEN_BRANCH_ICON_STYLE = {"font-size": "2.5em", "margin": "0 10px", "color": CYTO_COLORS["open_branch"]}
1312
LEGENDA_HTML = html.Div(
14-
[
15-
html.I(className="fas fa-circle", style=_NODE_ICON_STYLE),
16-
html.I(className="fas fa-diamond", style=_SUBSTATION_ICON_STYLE),
17-
html.I(className="fas fa-arrow-right-long", style=_LINE_ICON_STYLE),
18-
html.I(className="fas fa-arrow-right-long", style=_LINK_ICON_STYLE),
19-
html.I(className="fas fa-arrow-right-long", style=_TRANSFORMER_ICON_STYLE),
20-
html.I(className="fas fas fa-ellipsis", style=_OPEN_BRANCH_ICON_STYLE),
21-
],
13+
[
14+
html.I(className="fas fa-circle", id="node-icon", style=NODE_ICON_STYLE),
15+
dbc.Tooltip("Node", target="node-icon", placement="bottom"),
16+
html.I(className="fas fa-diamond", id="substation-icon", style=_SUBSTATION_ICON_STYLE),
17+
dbc.Tooltip("Substation", target="substation-icon", placement="bottom"),
18+
html.I(className="fas fa-arrow-right-long", id="line-icon", style=_LINE_ICON_STYLE),
19+
dbc.Tooltip("Line", target="line-icon", placement="bottom"),
20+
html.I(className="fas fa-arrow-right-long", id="transformer-icon", style=_TRANSFORMER_ICON_STYLE),
21+
dbc.Tooltip("Transformer", target="transformer-icon", placement="bottom"),
22+
html.I(className="fas fa-arrow-right-long", id="link-icon", style=_LINK_ICON_STYLE),
23+
dbc.Tooltip("Link", target="link-icon", placement="bottom"),
24+
html.I(className="fas fa-ellipsis", id="open-branch-icon", style=_OPEN_BRANCH_ICON_STYLE),
25+
dbc.Tooltip("Open Branch", target="open-branch-icon", placement="bottom"),
26+
],
27+
style={
28+
"display": "flex",
29+
"align-items": "center",
30+
"margin": "0 10px",
31+
"width": "100%",
32+
"text-shadow": "0 0 5px #000"
33+
}
2234
)
23-
24-
25-
# <i class="fas fa-ellipsis"></i>

src/power_grid_model_ds/_core/visualizer/layout/search_form.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import dash_bootstrap_components as dbc
22
from dash import html
33

4-
_SPAN_TEXT_STYLE = {"margin": "8px", "font-weight": "bold"}
4+
SPAN_TEXT_STYLE = {"color": "white", "margin-right": "8px", "font-weight": "bold", "text-shadow": "0 0 5px #000"}
55
_INPUT_STYLE = {"width": "150px", "display": "inline-block"}
66
# Create your form components
77
GROUP_INPUT = dbc.Select(
@@ -47,9 +47,9 @@
4747
# Arrange as a sentence
4848
SEARCH_FORM_HTML = html.Div(
4949
[
50-
html.Span("Search ", className="mr-2", style=_SPAN_TEXT_STYLE),
50+
html.Span("Search ", style=SPAN_TEXT_STYLE),
5151
GROUP_INPUT,
52-
html.Span(" with ", className="mx-2", style=_SPAN_TEXT_STYLE),
52+
html.Span(" with ", className="mx-2", style=SPAN_TEXT_STYLE),
5353
COLUMN_INPUT,
5454
OPERATOR_INPUT,
5555
VALUE_INPUT,
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from dash import dcc, html
22

33
SELECTION_OUTPUT_HEADER_STYLE = {"margin": "20px 0 10px 0"}
4-
_SELECTION_OUTPUT_STYLE = {"overflowX": "scroll", "textAlign": "center", "margin": "0 20px 20px 20px"}
4+
_SELECTION_OUTPUT_STYLE = {"overflowX": "scroll", "textAlign": "center", "margin": "10px"}
55

66
SELECTION_OUTPUT_HTML = html.Div(
77
dcc.Markdown("Click on a **node** or **edge** to display its attributes.", style=SELECTION_OUTPUT_HEADER_STYLE),
8-
id="search-output",
8+
id="selection-output",
99
style=_SELECTION_OUTPUT_STYLE,
1010
)

0 commit comments

Comments
 (0)