Simplification of layout selection (#384)

Removed the 2d/3d toggle and added that option into the layout dropdown.

---------

Co-authored-by: KM-R <129882581+KM-R@users.noreply.github.com>
This commit is contained in:
Philipp Horstenkamp 2023-11-14 22:31:30 +01:00 committed by GitHub
parent e7278c047e
commit 0d4d1324d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 69 deletions

View File

@ -31,7 +31,7 @@
display: inline-block; display: inline-block;
padding: 10px; padding: 10px;
width: 31%; width: 31%;
vertical-align: top;
} }
.networkx_style .filter-wrapper .filter-wrapper-item .dropdown_style { .networkx_style .filter-wrapper .filter-wrapper-item .dropdown_style {

View File

@ -8,6 +8,7 @@ import pandas as pd
import plotly.graph_objects as go import plotly.graph_objects as go
from cachetools import TTLCache, cached from cachetools import TTLCache, cached
from dash import Input, Output, callback, dash_table, dcc, html from dash import Input, Output, callback, dash_table, dcc, html
from loguru import logger
from aki_prj23_transparenzregister.utils.networkx.network_2d import ( from aki_prj23_transparenzregister.utils.networkx.network_2d import (
create_2d_graph, create_2d_graph,
@ -64,7 +65,6 @@ def update_table(
@cached(TTLCache(20, ttl=600)) @cached(TTLCache(20, ttl=600))
def _update_figure( # noqa: PLR0913 def _update_figure( # noqa: PLR0913
selected_metric: str, selected_metric: str,
switch_value: bool,
switch_edge_annotation_value: bool, switch_edge_annotation_value: bool,
c_relation_filter_value: frozenset[str], c_relation_filter_value: frozenset[str],
p_relation_filter_value: frozenset[str], p_relation_filter_value: frozenset[str],
@ -78,7 +78,6 @@ def _update_figure( # noqa: PLR0913
Args: Args:
selected_metric: Selected Value selected_metric: Selected Value
switch_value: True if 2D, False if 3D
switch_edge_annotation_value: True if Edge should have a description, False = No Description switch_edge_annotation_value: True if Edge should have a description, False = No Description
c_relation_filter_value: Variable with String value of Relation Type for Companies c_relation_filter_value: Variable with String value of Relation Type for Companies
p_relation_filter_value: Variable with String value of Relation Type for Persons p_relation_filter_value: Variable with String value of Relation Type for Persons
@ -91,7 +90,9 @@ def _update_figure( # noqa: PLR0913
Network Graph(Plotly Figure): Plotly Figure in 3 or 2D Network Graph(Plotly Figure): Plotly Figure in 3 or 2D
""" """
_ = c_relation_filter_value, p_relation_filter_value _ = c_relation_filter_value, p_relation_filter_value
dims = 3 if layout.endswith("(3d)") else 2
layout = layout[:-5].strip()
logger.info(f"Plotting full network for layout: {layout} with {dims} dimensions.")
graph, metrics, nodes, edges = update_graph_data( graph, metrics, nodes, edges = update_graph_data(
person_relation_type=p_relation_filter_value, person_relation_type=p_relation_filter_value,
company_relation_type=c_relation_filter_value, company_relation_type=c_relation_filter_value,
@ -99,7 +100,7 @@ def _update_figure( # noqa: PLR0913
table_dict, table_columns = update_table(metric_dropdown_value, metrics) table_dict, table_columns = update_table(metric_dropdown_value, metrics)
if switch_value: if dims == 2: # noqa: PLR2004
return ( return (
table_dict, table_dict,
table_columns, table_columns,
@ -148,10 +149,9 @@ def layout() -> list[html]:
top_companies_dict, top_companies_columns, figure = _update_figure( top_companies_dict, top_companies_columns, figure = _update_figure(
"None", "None",
False, False,
False,
selected_company_relation_types, selected_company_relation_types,
selected_person_relation_types, selected_person_relation_types,
"Spring", "Spring (3d)",
1, 1,
"degree", "degree",
) )
@ -199,14 +199,15 @@ def layout() -> list[html]:
html.Div( html.Div(
className="filter-wrapper", className="filter-wrapper",
id="company_dropdown", id="company_dropdown",
# style="visibility: hidden;",
children=[ children=[
html.Div( html.Div(
className="filter-wrapper-item", className="filter-wrapper-item",
children=[ children=[
html.H5( html.H5(
className="filter-description", className="filter-description",
children=["Company Relation Type Filter:"], children=[
"Show selected relations Company to Company:"
],
), ),
dcc.Dropdown( dcc.Dropdown(
company_relation_types, company_relation_types,
@ -220,11 +221,12 @@ def layout() -> list[html]:
), ),
html.Div( html.Div(
className="filter-wrapper-item", className="filter-wrapper-item",
# style="visibility: visible;",
children=[ children=[
html.H5( html.H5(
className="filter-description", className="filter-description",
children=["Person Relation Type Filter:"], children=[
"Show selected relations Company to Person:"
],
), ),
dcc.Dropdown( dcc.Dropdown(
person_relation_types, person_relation_types,
@ -266,20 +268,25 @@ def layout() -> list[html]:
), ),
dcc.Dropdown( dcc.Dropdown(
[ [
"Spring", "Spring (2d)",
"Spring (3d)",
# "Bipartite", # "Bipartite",
"Circular", "Circular (2d)",
"Kamada Kawai", "Circular (3d)",
"Kamada Kawai (2d)",
"Kamada Kawai (3d)",
# "Planar", # "Planar",
"Random", "Random (2d)",
"Shell (only 2D)", "Random (3d)",
"Shell (2d)",
# "Spectral", # "Spectral",
"Spiral (only 2D)", "Spiral (2d)",
# "Multipartite" # "Multipartite"
], ],
"Spring", "Spring (3d)",
id="dropdown_layout", id="dropdown_layout",
className="dropdown_style", className="dropdown_style",
placeholder="Select a graph layout",
), ),
], ],
), ),
@ -299,39 +306,6 @@ def layout() -> list[html]:
), ),
], ],
), ),
],
),
html.Div(
className="filter-wrapper",
children=[
html.Div(
className="filter-wrapper-item",
children=[
html.H5(
className="filter-description",
children=["Switch to 2D Diagramm"],
),
html.Div(
className="switch-style",
children=[
daq.BooleanSwitch(id="switch", on=False)
],
),
],
),
# html.Div(
# className="filter-wrapper-item",
# children=[
# html.H5(
# className="filter-description",
# children=["Enable Node Annotation"],
# ),
# html.Div(
# className="switch-style",
# children=[daq.BooleanSwitch(id="switch_node_annotation", on=False)],
# ),
# ],
# ),
html.Div( html.Div(
className="filter-wrapper-item", className="filter-wrapper-item",
children=[ children=[
@ -370,15 +344,7 @@ def update_graph_data(
person_relation_type: frozenset[str] | None = None, person_relation_type: frozenset[str] | None = None,
company_relation_type: frozenset[str] | None = None, company_relation_type: frozenset[str] | None = None,
) -> tuple[nx.Graph, pd.DataFrame, dict, list]: ) -> tuple[nx.Graph, pd.DataFrame, dict, list]:
"""_summary_. """_summary_."""
Args:
person_relation_type (str, optional): _description_. Defaults to "HAFTENDER_GESELLSCHAFTER".
company_relation_type (str, optional): _description_. Defaults to "GESCHAEFTSFUEHRER".
Returns:
tuple[nx.Graph, pd.DataFrame, dict, list]: _description_
"""
person_df = get_all_person_relations() person_df = get_all_person_relations()
company_df = get_all_company_relations() company_df = get_all_company_relations()
@ -400,7 +366,6 @@ def update_graph_data(
], ],
[ [
Input("dropdown", "value"), Input("dropdown", "value"),
Input("switch", "on"),
# Input("switch_node_annotation", "on"), # Input("switch_node_annotation", "on"),
Input("switch_edge_annotation", "on"), Input("switch_edge_annotation", "on"),
Input("dropdown_company_relation_filter", "value"), Input("dropdown_company_relation_filter", "value"),
@ -414,7 +379,6 @@ def update_graph_data(
) )
def update_figure( # noqa: PLR0913 def update_figure( # noqa: PLR0913
selected_metric: str, selected_metric: str,
switch_value: bool,
switch_edge_annotation_value: bool, switch_edge_annotation_value: bool,
c_relation_filter_value: list[str], c_relation_filter_value: list[str],
p_relation_filter_value: list[str], p_relation_filter_value: list[str],
@ -428,7 +392,6 @@ def update_figure( # noqa: PLR0913
Args: Args:
selected_metric: Selected Value selected_metric: Selected Value
switch_value: True if 2D, False if 3D
switch_edge_annotation_value: True if Edge should have a description, False = No Description switch_edge_annotation_value: True if Edge should have a description, False = No Description
c_relation_filter_value: Variable with String value of Relation Type for Companies c_relation_filter_value: Variable with String value of Relation Type for Companies
p_relation_filter_value: Variable with String value of Relation Type for Persons p_relation_filter_value: Variable with String value of Relation Type for Persons
@ -440,9 +403,10 @@ def update_figure( # noqa: PLR0913
Returns: Returns:
Network Graph: Plotly Figure in 3D or 2D Network Graph: Plotly Figure in 3D or 2D
""" """
if not layout:
return dash.no_update
return _update_figure( return _update_figure(
selected_metric, selected_metric,
switch_value,
switch_edge_annotation_value, switch_edge_annotation_value,
frozenset(c_relation_filter_value), frozenset(c_relation_filter_value),
frozenset(p_relation_filter_value), frozenset(p_relation_filter_value),

View File

@ -45,11 +45,11 @@ def create_2d_graph( # noqa PLR0913
# pos = nx.planar_layout(graph) # pos = nx.planar_layout(graph)
case "Random": case "Random":
pos = nx.random_layout(graph) pos = nx.random_layout(graph)
case "(Shell only 2D)": case "Shell":
pos = nx.shell_layout(graph) pos = nx.shell_layout(graph)
# case "Spectral": # case "Spectral":
# pos = nx.spectral_layout(graph) # pos = nx.spectral_layout(graph)
case "(Spiral only 2D)": case "Spiral":
pos = nx.spiral_layout(graph) pos = nx.spiral_layout(graph)
# case "Multipartite": # case "Multipartite":
# pos = nx.multipartite_layout(graph) # pos = nx.multipartite_layout(graph)

View File

@ -5,8 +5,10 @@ from unittest.mock import patch
import pandas as pd import pandas as pd
import pytest import pytest
from sqlalchemy.orm import Session
from aki_prj23_transparenzregister.ui.pages import home from aki_prj23_transparenzregister.ui.pages import home
from aki_prj23_transparenzregister.ui.session_handler import SessionHandler
def test_import() -> None: def test_import() -> None:
@ -14,7 +16,6 @@ def test_import() -> None:
assert home is not None assert home is not None
@pytest.mark.tim()
def test_person_relation_type_filter() -> None: def test_person_relation_type_filter() -> None:
with patch( with patch(
"aki_prj23_transparenzregister.ui.pages.home.get_all_person_relations" "aki_prj23_transparenzregister.ui.pages.home.get_all_person_relations"
@ -28,7 +29,6 @@ def test_person_relation_type_filter() -> None:
assert list(home.person_relation_type_filter()) == ["Eigentümer", "Inhaber"] assert list(home.person_relation_type_filter()) == ["Eigentümer", "Inhaber"]
@pytest.mark.tim()
def test_company_relation_type_filter() -> None: def test_company_relation_type_filter() -> None:
with patch( with patch(
"aki_prj23_transparenzregister.ui.pages.home.get_all_company_relations" "aki_prj23_transparenzregister.ui.pages.home.get_all_company_relations"
@ -42,7 +42,6 @@ def test_company_relation_type_filter() -> None:
assert list(home.company_relation_type_filter()) == ["Eigentümer", "Inhaber"] assert list(home.company_relation_type_filter()) == ["Eigentümer", "Inhaber"]
@pytest.mark.tim()
def test_update_table() -> None: def test_update_table() -> None:
metrics = pd.DataFrame( metrics = pd.DataFrame(
[ [
@ -192,3 +191,17 @@ def test_update_graph_data() -> None:
frozenset({"HAFTENDER_GESELLSCHAFTER"}), frozenset("GESCHAEFTSFUEHRER") frozenset({"HAFTENDER_GESELLSCHAFTER"}), frozenset("GESCHAEFTSFUEHRER")
) )
assert graph_result is not None assert graph_result is not None
@pytest.fixture()
def _set_session(full_db: Session) -> Generator[None, None, None]:
"""Sets a session for the dash application to be used."""
SessionHandler.session = full_db
yield
SessionHandler.session = None
@pytest.mark.usefixtures("_set_session")
def test_layout() -> None:
"""Checks if layout can be executed."""
home.layout()