commit b4b7a5cad1f79dc195eeea47840f9f5548be77cf
parent 66c432e6d16a2f78e1fbd543b083b4031ba7aac5
Author: Andy Khramtsov <>
Date: Sun, 31 May 2026 18:07:16 +0300
feat: visualize sugraph down or up
Diffstat:
1 file changed, 57 insertions(+), 29 deletions(-)
diff --git a/src/rsdeps/pages/home.py b/src/rsdeps/pages/home.py
@@ -40,7 +40,8 @@ class ids:
class toggle_values:
- subtree: str = "subtree"
+ subgraph_down: str = "subgraph_down"
+ subgraph_up: str = "subgraph_up"
class colors:
@@ -248,7 +249,10 @@ def layout():
id=ids.toggles,
inline=True,
persistence=True,
- options=[dict(label="Subtree", value=toggle_values.subtree)],
+ options=[
+ dict(label="Subgraph down", value=toggle_values.subgraph_down),
+ dict(label="Subgraph up", value=toggle_values.subgraph_up),
+ ],
),
],
),
@@ -450,35 +454,51 @@ def draw_graph_figure(
positions: dict[str, tuple[float, float]],
adjacency_list: dict[str, set[str]],
selected_node=None,
- subtree: bool = False,
+ subgraph_down: bool = False,
+ subgraph_up: bool = False,
) -> go.Figure:
highlight_nodes = set()
if selected_node and selected_node in adjacency_list:
highlight_nodes.add(selected_node)
highlight_nodes.update(adjacency_list[selected_node])
- subtree_nodes = set()
-
- def build_subtree():
- node_buffer = []
- if selected_node:
- node_buffer.append(selected_node)
- subtree_nodes.add(selected_node)
-
- graph = {str(node): set() for node in df_graph.nodes["node_id"]}
- for arc in df_graph.arcs.iter_rows(named=True):
- if arc["target"] is not None:
- graph[str(arc["source"])].add(str(arc["target"]))
-
- while node_buffer:
- source = node_buffer.pop()
- for target in graph[source]:
- if target not in subtree_nodes:
- node_buffer.append(target)
- subtree_nodes.add(target)
-
- if subtree:
- build_subtree()
+ def build_subgraph():
+
+ def build_from_dict(graph: dict, subgraph: set):
+ node_buffer = []
+ if selected_node:
+ node_buffer.append(selected_node)
+ subgraph.add(selected_node)
+ while node_buffer:
+ source = node_buffer.pop()
+ for target in graph[source]:
+ if target not in subgraph:
+ node_buffer.append(target)
+ subgraph.add(target)
+
+ subgraph_up_nodes = set()
+ subgraph_down_nodes = set()
+
+ if subgraph_down:
+ graph = {str(node): set() for node in df_graph.nodes["node_id"]}
+ for arc in df_graph.arcs.iter_rows(named=True):
+ if arc["target"] is not None:
+ graph[str(arc["source"])].add(str(arc["target"]))
+ build_from_dict(graph, subgraph_down_nodes)
+
+ if subgraph_up:
+ graph = {str(node): set() for node in df_graph.nodes["node_id"]}
+ for arc in df_graph.arcs.iter_rows(named=True):
+ if arc["target"] is not None:
+ graph[str(arc["target"])].add(str(arc["source"]))
+ build_from_dict(graph, subgraph_down_nodes)
+
+ return subgraph_down_nodes.union(subgraph_up_nodes)
+
+ subgraph_nodes = set()
+ subgraph = selected_node and (subgraph_down or subgraph_up)
+ if subgraph:
+ subgraph_nodes = build_subgraph()
edges = EdgeFigData(
x=[],
@@ -509,7 +529,7 @@ def draw_graph_figure(
):
edges_highlight.x.extend([source_x, target_x, None])
edges_highlight.y.extend([source_y, target_y, None])
- elif selected_node and (not subtree or source not in subtree_nodes or target not in subtree_nodes):
+ elif selected_node and (not subgraph or source not in subgraph_nodes or target not in subgraph_nodes):
edges_faint.x.extend([source_x, target_x, None])
edges_faint.y.extend([source_y, target_y, None])
else:
@@ -550,7 +570,7 @@ def draw_graph_figure(
if selected_node:
if node_id in highlight_nodes:
nodes_appending = nodes_highlight
- elif subtree and node_id in subtree_nodes:
+ elif subgraph and node_id in subgraph_nodes:
nodes_appending = nodes
else:
nodes_appending = nodes_faint
@@ -842,7 +862,8 @@ def graph_update(inputs, state):
selected = state["selected_node_store"].get("selected")
toggles = inputs["toggles"] or []
- subtree = toggle_values.subtree in toggles
+ subgraph_down = toggle_values.subgraph_down in toggles
+ subgraph_up = toggle_values.subgraph_up in toggles
positions = state["cache"]["positions"]
adjacency_list = unwrap_adjacency_list(state["cache"]["adjacency_list"])
@@ -864,7 +885,14 @@ def graph_update(inputs, state):
old_fig = state["figure"]
uirevision = old_fig.get("layout", {}).get("uirevision", 0)
- fig = draw_graph_figure(df_graph, positions, adjacency_list, selected, subtree)
+ fig = draw_graph_figure(
+ df_graph,
+ positions,
+ adjacency_list,
+ selected,
+ subgraph_down,
+ subgraph_up,
+ )
fig.update_layout(uirevision=uirevision)
return dict(