commit 05a2206867b1e62159e09e8aa9f083b8c1001ef5
parent cf3a1dda0282c09daee28f73b5c6e095dcf5eb78
Author: Andy Khramtsov <>
Date: Thu, 28 May 2026 01:05:04 +0300
feat: cache graph
Diffstat:
1 file changed, 46 insertions(+), 16 deletions(-)
diff --git a/src/deps/pages/home.py b/src/deps/pages/home.py
@@ -1,4 +1,5 @@
import base64
+import io
import tomllib
import dash
@@ -30,6 +31,8 @@ class ids:
dependency_graph: str = "dependency-graph"
reset_highlight_button: str = "reset-highlight-button"
+ cache_store: str = "cache-store"
+
def layout():
return html.Div(
@@ -37,6 +40,7 @@ def layout():
children=[
html.H2("Cargo dependency visualisation"),
html.H3("Cargo toml"),
+ dcc.Store(id=ids.cache_store, storage_type="memory"),
dcc.Textarea(
id=ids.cargo_toml_textarea,
placeholder="Cargo.toml contents",
@@ -394,9 +398,7 @@ def display_cargo_lock_packages(inputs, state):
@callback(
- dict(
- graph=Output(ids.dependency_graph, "figure"),
- ),
+ dict(graph=Output(ids.dependency_graph, "figure"), cache=Output(ids.cache_store, "data")),
dict(
generate=Input(ids.generate_button, "n_clicks"),
click_data=Input(ids.dependency_graph, "clickData"),
@@ -405,29 +407,57 @@ def display_cargo_lock_packages(inputs, state):
dict(
cargo_toml=State(ids.cargo_toml_textarea, "value"),
cargo_lock=State(ids.cargo_lock_textarea, "value"),
+ cache=State(ids.cache_store, "data"),
),
)
def visualize(inputs, state):
- if not state["cargo_toml"] or not state["cargo_lock"]:
- raise PreventUpdate
- try:
- cargo_toml = parse_cargo_toml(state["cargo_toml"])
- cargo_lock = parse_cargo_lock(state["cargo_lock"])
- except tomllib.TOMLDecodeError as error:
- raise PreventUpdate from error
+ if ctx.triggered_id and ctx.triggered_id == ids.generate_button:
+ print("clean")
+ clean = True
+ if (
+ not state["cache"]
+ or state["cache"].get("positions") is None
+ or state["cache"].get("df_graph_nodes") is None
+ or state["cache"].get("df_graph_arcs") is None
+ ):
+ clean = True
+ else:
+ clean = False
- selected = None
if ctx.triggered_id and ctx.triggered_id == ids.reset_highlight_button:
selected = None
- elif inputs["click_data"] and "points" in inputs["click_data"]:
+ elif inputs["click_data"] and "points" in inputs["click_data"] and not clean:
point = inputs["click_data"]["points"][0]
- if "customdata" in point:
- selected = point["customdata"]
+ selected = point.get("customdata", None)
+ else:
+ selected = None
+
+ if clean:
+ if not state["cargo_toml"] or not state["cargo_lock"]:
+ raise PreventUpdate
+ try:
+ cargo_toml = parse_cargo_toml(state["cargo_toml"])
+ cargo_lock = parse_cargo_lock(state["cargo_lock"])
+ except tomllib.TOMLDecodeError as error:
+ raise PreventUpdate from error
+ df_graph = parse_graph(cargo_toml, cargo_lock)
+ positions = compute_positions(df_graph)
+ cache = {
+ "positions": positions,
+ "df_graph_nodes": df_graph["nodes"].serialize(format="json"),
+ "df_graph_arcs": df_graph["arcs"].serialize(format="json"),
+ }
+ else:
+ positions = state["cache"]["positions"]
+ df_graph = dict(
+ nodes=pl.DataFrame.deserialize(io.StringIO(state["cache"]["df_graph_nodes"]), format="json"),
+ arcs=pl.DataFrame.deserialize(io.StringIO(state["cache"]["df_graph_arcs"]), format="json"),
+ )
+ cache = dash.no_update
- df_graph = parse_graph(cargo_toml, cargo_lock)
- positions = compute_positions(df_graph)
fig = draw_graph_figure(df_graph, positions, selected)
return dict(
graph=fig,
+ cache=cache,
)