diff --git a/src/aki_prj23_transparenzregister/ui/assets/networkx_style.css b/src/aki_prj23_transparenzregister/ui/assets/networkx_style.css index ca5d9c7..a00fd21 100644 --- a/src/aki_prj23_transparenzregister/ui/assets/networkx_style.css +++ b/src/aki_prj23_transparenzregister/ui/assets/networkx_style.css @@ -74,6 +74,7 @@ margin-top: 1px; padding-left: 10px; width: 80%; + display: inline-block; /* background-color: var(--raisin-black); */ } @@ -81,7 +82,7 @@ .networkx_style .switch-style .jAjsxw { align-self: left; float: none; - display: inline; + display: inline-block; padding: 0px; margin: 0px; @@ -90,12 +91,14 @@ } .networkx_style .graph-style { + margin-top: 10px; padding-bottom: 0px; - display: inline; + display: inline-block; margin: 0px; width: 100%; height: 100%; + /* float: inline-end, */ /* background-color: var(--raisin-black); */ } diff --git a/src/aki_prj23_transparenzregister/ui/pages/home.py b/src/aki_prj23_transparenzregister/ui/pages/home.py index 865366f..2e94082 100644 --- a/src/aki_prj23_transparenzregister/ui/pages/home.py +++ b/src/aki_prj23_transparenzregister/ui/pages/home.py @@ -56,6 +56,18 @@ graph, metrices = initialize_network(nodes = nodes, edges = edges) # print(graph) metric = None network = create_3d_graph(graph, nodes, edges, metrics, metric) +# Create Edge and Node List from data +nodes, edges = create_edge_and_node_list(person_relation, company_relation) +# Initialize the Network and receive the Graph and a DataFrame with Metrics +node_count = len(nodes) +edge_count = len(edges) +graph, metrics = initialize_network(nodes=nodes, edges=edges) +metric = "None" +layout = "Spring" +switch_node_annotaion_value = False +switch_edge_annotaion_value = True +egde_thickness = 1 +network = create_3d_graph(graph, nodes, edges, metrics, metric, layout, switch_node_annotaion_value, switch_edge_annotaion_value, egde_thickness) # Get the possible Filter values for the Dropdowns. company_relation_type_filter = get_all_person_relations()["relation_type"].unique() @@ -136,21 +148,112 @@ layout = html.Div( ), ], ), + html.Div( + className="filter-wrapper-item", + children=[ + html.H5( + className="filter-description", + children=["Choose Layout:"], + ), + dcc.Dropdown( + [ + "Spring", + # "Bipartite", + "Circular", + "Kamada Kawai", + "Planar", + "Random", + "Shell", + "Spectral", + "Spiral", + "Multipartite" + ], + "Spring", + id="dropdown_layout", + className="dropdown_style", + ), + ], + ), + html.Div( + className="filter-wrapper-item", + children=[ + html.H5( + className="filter-description", + children=["Adjust Edge Thickness"], + ), + dcc.Slider( 1, 4, 1, + value=1, + id='slider', + ), + ],), ], ), html.Div( - className="filter-wrapper-item", + className="filter-wrapper", children=[ - html.H5( - className="filter-description", - children=["Switch to 2D Diagramm"], + 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="switch-style", - children=[daq.BooleanSwitch(id="switch", on=False)], + 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=[ + html.H5( + className="filter-description", + children=["Enable Edge Annotation"], + ), + html.Div( + className="switch-style", + children=[daq.BooleanSwitch(id="switch_edge_annotation", on=False)], + ), + ], ), ], ), + html.Div( + className="filter-wrapper", + children=[ + html.Div( + className="filter-wrapper-item", + children=[ + html.H5( + className="filter-description", + children=[f"""Number of shown Nodes: {node_count}"""], + ), + ],), + html.Div( + className="filter-wrapper-item", + children=[ + html.H5( + className="filter-description", + children=[f"""Number of shown Edges: {edge_count}"""], + ), + ],), + ], + ), + dcc.Graph(figure=network, id="my-graph", className="graph-style"), ], ), @@ -174,6 +277,8 @@ def update_graph_data( # Create Edge and Node List from data nodes, edges = create_edge_and_node_list(person_relation, company_relation) + # node_count = len(nodes) + # edge_count = len(edges) graph, metrics = initialize_network(nodes=nodes, edges=edges) return graph, metrics @@ -184,8 +289,12 @@ 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"), Input("dropdown_person_relation_filter", "value"), + Input("dropdown_layout", "value"), + Input('slider', 'value') ], prevent_initial_call=True, allow_duplicate=True, @@ -194,8 +303,12 @@ def update_graph_data( def update_figure( selected_metric: str, switch_value: bool, + switch_node_annotaion_value: bool, + switch_edge_annotaion_value: bool, c_relation_filter_value: str, p_relation_filter_value: str, + layout: str, + slider_value: float ) -> go.Figure: """In this Callback the Value of the Dropdown is used to filter the Data. In Addition it takes the filter for the Graph metrics and creates a new graph, or switches between 3D and 2D. @@ -217,10 +330,11 @@ def update_figure( # print(graph) graph, metrics = update_graph_data(person_relation_type= p_relation_filter_value, company_relation_type= c_relation_filter_value) + if switch_value: - return create_2d_graph(graph, nodes, edges, metrics, selected_metric) + return create_2d_graph(graph, nodes, edges, metrics, selected_metric, layout, switch_node_annotaion_value, switch_edge_annotaion_value, slider_value) else: - return create_3d_graph(graph, nodes, edges, metrics, selected_metric) + return create_3d_graph(graph, nodes, edges, metrics, selected_metric, layout, switch_node_annotaion_value, switch_edge_annotaion_value, slider_value) diff --git a/src/aki_prj23_transparenzregister/utils/networkx/network_2d.py b/src/aki_prj23_transparenzregister/utils/networkx/network_2d.py index d6af5f3..c4a1cd8 100644 --- a/src/aki_prj23_transparenzregister/utils/networkx/network_2d.py +++ b/src/aki_prj23_transparenzregister/utils/networkx/network_2d.py @@ -6,7 +6,7 @@ import plotly.graph_objects as go def create_2d_graph( - graph: nx.Graph, nodes: dict, edges: list, metrics: pd.DataFrame, metric: str | None + graph: nx.Graph, nodes: dict, edges: list, metrics: pd.DataFrame, metric: str | None, layout: str, node_annotation: bool, edge_annotation: bool, edge_thickness: int ) -> go.Figure: """This Method creates a 2d Network in Plotly with a Scatter Graph and retuns it. @@ -20,8 +20,29 @@ def create_2d_graph( Returns: _type_: Plotly Figure """ - # Set 2D Layout + # Set 2D Layout pos = nx.spring_layout(graph) + match layout: + case "Spring": + pos = nx.spring_layout(graph) + # case "Bipartite": + # pos = nx.bipartite_layout(graph) + case "Circular": + pos = nx.circular_layout(graph) + case "Kamada Kawai": + pos = nx.kamada_kawai_layout(graph) + # case "Planar": + # pos = nx.planar_layout(graph) + case "Random": + pos = nx.random_layout(graph) + case "Shell": + pos = nx.shell_layout(graph) + # case "Spectral": + # pos = nx.spectral_layout(graph) + case "Spiral": + pos = nx.spiral_layout(graph) + # case "Multipartite": + # pos = nx.multipartite_layout(graph) # Initialize Variables to set the Position of the Edges. edge_x = [] @@ -90,7 +111,7 @@ def create_2d_graph( "xanchor": "left", "titleside": "right", }, - "line_width": 2, + "line_width": edge_thickness, }, ) @@ -111,12 +132,17 @@ def create_2d_graph( if metric != "None": node_trace.marker.size = list(np.sqrt(metrics[metric]) * 200) - # Add Relation_Type as a Descriptin for the edges. - edge_type_list = [] - for row in edges: - edge_type_list.append(row["type"]) + # Add Relation_Type as a Description for the edges. + if edge_annotation: + edge_type_list = [] + for row in edges: + edge_type_list.append(row["type"]) - edge_weights_trace.text = edge_type_list + edge_weights_trace.text = edge_type_list + + if node_annotation: + print("Test") + # node_trace.text = nodes. # Return the Plotly Figure return go.Figure( diff --git a/src/aki_prj23_transparenzregister/utils/networkx/network_3d.py b/src/aki_prj23_transparenzregister/utils/networkx/network_3d.py index f3a88a6..4f53a5d 100644 --- a/src/aki_prj23_transparenzregister/utils/networkx/network_3d.py +++ b/src/aki_prj23_transparenzregister/utils/networkx/network_3d.py @@ -6,7 +6,7 @@ import plotly.graph_objects as go def create_3d_graph( - graph: nx.Graph, nodes: dict, edges: list, metrics: pd.DataFrame, metric: str | None + graph: nx.Graph, nodes: dict, edges: list, metrics: pd.DataFrame, metric: str | None, layout: str, node_annotation: bool, edge_annotation: bool, edge_thickness: int ) -> go.Figure: """This Method creates a 3D Network in Plotly with a Scatter Graph and retuns it. @@ -21,7 +21,28 @@ def create_3d_graph( _type_: Plotly Figure """ # 3d spring layout - pos = nx.spring_layout(graph, dim=3, seed=779) + pos = nx.spring_layout(graph, dim=3) + match layout: + case "Spring": + pos = nx.spring_layout(graph, dim=3) + # case "Bipartite": + # pos = nx.bipartite_layout(graph, dim=3) + case "Circular": + pos = nx.circular_layout(graph, dim=3) + case "Kamada Kawai": + pos = nx.kamada_kawai_layout(graph, dim=3) + # case "Planar": + # pos = nx.planar_layout(graph, dim=3) + case "Random": + pos = nx.random_layout(graph, dim=3) + # case "Shell": + # pos = nx.shell_layout(graph, dim=3) + # case "Spectral": + # pos = nx.spectral_layout(graph, dim=3) + # case "Spiral": + # pos = nx.spiral_layout(graph, dim=3) + # case "Multipartite": + # pos = nx.multipartite_layout(graph, dim=3) # Initialize Variables to set the Position of the Edges. edge_x = [] @@ -140,7 +161,7 @@ def create_3d_graph( edge_colors.append("rgb(255,0,0)") else: edge_colors.append("rgb(255,105,180)") - edge_trace.line = {"color": edge_colors, "width": 2} + edge_trace.line = {"color": edge_colors, "width": edge_thickness} # Return the Plotly Figure data = [edge_trace, node_trace]