diff --git a/src/aki_prj23_transparenzregister/ui/assets/networkx_style.css b/src/aki_prj23_transparenzregister/ui/assets/networkx_style.css index 949ee57..9f1f434 100644 --- a/src/aki_prj23_transparenzregister/ui/assets/networkx_style.css +++ b/src/aki_prj23_transparenzregister/ui/assets/networkx_style.css @@ -31,7 +31,7 @@ display: inline-block; padding: 10px; width: 31%; - + vertical-align: top; } .networkx_style .filter-wrapper .filter-wrapper-item .dropdown_style { diff --git a/src/aki_prj23_transparenzregister/ui/pages/home.py b/src/aki_prj23_transparenzregister/ui/pages/home.py index dd7e67d..e2a65ce 100644 --- a/src/aki_prj23_transparenzregister/ui/pages/home.py +++ b/src/aki_prj23_transparenzregister/ui/pages/home.py @@ -8,6 +8,7 @@ import pandas as pd import plotly.graph_objects as go from cachetools import TTLCache, cached from dash import Input, Output, callback, dash_table, dcc, html +from loguru import logger from aki_prj23_transparenzregister.utils.networkx.network_2d import ( create_2d_graph, @@ -64,7 +65,6 @@ def update_table( @cached(TTLCache(20, ttl=600)) def _update_figure( # noqa: PLR0913 selected_metric: str, - switch_value: bool, switch_edge_annotation_value: bool, c_relation_filter_value: frozenset[str], p_relation_filter_value: frozenset[str], @@ -78,7 +78,6 @@ def _update_figure( # noqa: PLR0913 Args: 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 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 @@ -91,7 +90,9 @@ def _update_figure( # noqa: PLR0913 Network Graph(Plotly Figure): Plotly Figure in 3 or 2D """ _ = 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( person_relation_type=p_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) - if switch_value: + if dims == 2: # noqa: PLR2004 return ( table_dict, table_columns, @@ -148,10 +149,9 @@ def layout() -> list[html]: top_companies_dict, top_companies_columns, figure = _update_figure( "None", False, - False, selected_company_relation_types, selected_person_relation_types, - "Spring", + "Spring (3d)", 1, "degree", ) @@ -199,14 +199,15 @@ def layout() -> list[html]: html.Div( className="filter-wrapper", id="company_dropdown", - # style="visibility: hidden;", children=[ html.Div( className="filter-wrapper-item", children=[ html.H5( className="filter-description", - children=["Company Relation Type Filter:"], + children=[ + "Show selected relations Company to Company:" + ], ), dcc.Dropdown( company_relation_types, @@ -220,11 +221,12 @@ def layout() -> list[html]: ), html.Div( className="filter-wrapper-item", - # style="visibility: visible;", children=[ html.H5( className="filter-description", - children=["Person Relation Type Filter:"], + children=[ + "Show selected relations Company to Person:" + ], ), dcc.Dropdown( person_relation_types, @@ -266,20 +268,25 @@ def layout() -> list[html]: ), dcc.Dropdown( [ - "Spring", + "Spring (2d)", + "Spring (3d)", # "Bipartite", - "Circular", - "Kamada Kawai", + "Circular (2d)", + "Circular (3d)", + "Kamada Kawai (2d)", + "Kamada Kawai (3d)", # "Planar", - "Random", - "Shell (only 2D)", + "Random (2d)", + "Random (3d)", + "Shell (2d)", # "Spectral", - "Spiral (only 2D)", + "Spiral (2d)", # "Multipartite" ], - "Spring", + "Spring (3d)", id="dropdown_layout", 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( className="filter-wrapper-item", children=[ @@ -370,15 +344,7 @@ def update_graph_data( person_relation_type: frozenset[str] | None = None, company_relation_type: frozenset[str] | None = None, ) -> tuple[nx.Graph, pd.DataFrame, dict, list]: - """_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_ - """ + """_summary_.""" person_df = get_all_person_relations() company_df = get_all_company_relations() @@ -400,7 +366,6 @@ def update_graph_data( ], [ Input("dropdown", "value"), - Input("switch", "on"), # Input("switch_node_annotation", "on"), Input("switch_edge_annotation", "on"), Input("dropdown_company_relation_filter", "value"), @@ -414,7 +379,6 @@ def update_graph_data( ) def update_figure( # noqa: PLR0913 selected_metric: str, - switch_value: bool, switch_edge_annotation_value: bool, c_relation_filter_value: list[str], p_relation_filter_value: list[str], @@ -428,7 +392,6 @@ def update_figure( # noqa: PLR0913 Args: 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 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 @@ -440,9 +403,10 @@ def update_figure( # noqa: PLR0913 Returns: Network Graph: Plotly Figure in 3D or 2D """ + if not layout: + return dash.no_update return _update_figure( selected_metric, - switch_value, switch_edge_annotation_value, frozenset(c_relation_filter_value), frozenset(p_relation_filter_value), diff --git a/src/aki_prj23_transparenzregister/utils/networkx/network_2d.py b/src/aki_prj23_transparenzregister/utils/networkx/network_2d.py index a5d3b8e..f8ba42c 100644 --- a/src/aki_prj23_transparenzregister/utils/networkx/network_2d.py +++ b/src/aki_prj23_transparenzregister/utils/networkx/network_2d.py @@ -45,11 +45,11 @@ def create_2d_graph( # noqa PLR0913 # pos = nx.planar_layout(graph) case "Random": pos = nx.random_layout(graph) - case "(Shell only 2D)": + case "Shell": pos = nx.shell_layout(graph) # case "Spectral": # pos = nx.spectral_layout(graph) - case "(Spiral only 2D)": + case "Spiral": pos = nx.spiral_layout(graph) # case "Multipartite": # pos = nx.multipartite_layout(graph) diff --git a/tests/ui/home_page_test.py b/tests/ui/home_page_test.py index 655fceb..e00d118 100644 --- a/tests/ui/home_page_test.py +++ b/tests/ui/home_page_test.py @@ -5,8 +5,10 @@ from unittest.mock import patch import pandas as pd import pytest +from sqlalchemy.orm import Session from aki_prj23_transparenzregister.ui.pages import home +from aki_prj23_transparenzregister.ui.session_handler import SessionHandler def test_import() -> None: @@ -14,7 +16,6 @@ def test_import() -> None: assert home is not None -@pytest.mark.tim() def test_person_relation_type_filter() -> None: with patch( "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"] -@pytest.mark.tim() def test_company_relation_type_filter() -> None: with patch( "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"] -@pytest.mark.tim() def test_update_table() -> None: metrics = pd.DataFrame( [ @@ -192,3 +191,17 @@ def test_update_graph_data() -> None: frozenset({"HAFTENDER_GESELLSCHAFTER"}), frozenset("GESCHAEFTSFUEHRER") ) 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()