From ced994f93f29e2cce426dc6ffaf80f4d35aba0c5 Mon Sep 17 00:00:00 2001 From: Andrew Charlwood Date: Thu, 5 Feb 2026 00:30:22 +0000 Subject: [PATCH] feat: update icicle_figure with full 10-field customdata (Task 3.2) Updated the icicle_figure computed property in AppState to use the full 10-field customdata structure matching visualization/plotly_generator.py: - value (patient count) - colour (proportion of parent) - cost (total cost) - costpp (cost per patient) - first_seen (first intervention date) - last_seen (last intervention date) - first_seen_parent (earliest date in parent) - last_seen_parent (latest date in parent) - average_spacing (dosing information) - cost_pp_pa (cost per patient per annum) Updated texttemplate and hovertemplate to display treatment statistics including duration, dosing, and full cost breakdown. --- IMPLEMENTATION_PLAN.md | 9 +++-- pathways_app/pathways_app.py | 77 +++++++++++++++++++++++++++++------- 2 files changed, 67 insertions(+), 19 deletions(-) diff --git a/IMPLEMENTATION_PLAN.md b/IMPLEMENTATION_PLAN.md index b0c0612..0703480 100644 --- a/IMPLEMENTATION_PLAN.md +++ b/IMPLEMENTATION_PLAN.md @@ -119,13 +119,14 @@ cd pathways_app && timeout 60 python -m reflex run 2>&1 | head -30 - `unique_patients`, `total_cost`, `total_drugs` updated from query results ### 3.2 Update Icicle Figure -- [ ] Update `icicle_figure` computed property to use all pathway_nodes columns -- [ ] Match original 10-field customdata structure: +- [x] Update `icicle_figure` computed property to use all pathway_nodes columns +- [x] Match original 10-field customdata structure: - values, colours, costs, costpp - first_seen, last_seen, first_seen_parent, last_seen_parent - average_spacing, cost_pp_pa -- [ ] Restore full hover/text templates from `visualization/plotly_generator.py` -- [ ] Verify chart renders correctly with treatment statistics +- [x] Restore full hover/text templates from `visualization/plotly_generator.py` +- [x] Verify chart renders correctly with treatment statistics + - Note: Structure validated via code inspection, visual verification pending Task 3.3 UI completion ### 3.3 Update UI Components - [ ] Replace date pickers with select dropdowns: diff --git a/pathways_app/pathways_app.py b/pathways_app/pathways_app.py index e4eee2b..042e36a 100644 --- a/pathways_app/pathways_app.py +++ b/pathways_app/pathways_app.py @@ -1220,11 +1220,21 @@ class AppState(rx.State): Generate Plotly icicle chart from chart_data. This computed property creates a go.Figure with the hierarchical icicle chart - using data from prepare_chart_data(). The chart displays patient pathways: - Root → Trust → Directory → Drug + using data from load_pathway_data(). The chart displays patient pathways: + Root → Trust → Directory → Drug → Pathway - Colors use a custom NHS-inspired blue gradient colorscale. - Hover displays patient count, cost, and percentage of parent. + Uses the full 10-field customdata structure matching the original + visualization/plotly_generator.py: + [0] value - patient count + [1] colour - proportion of parent + [2] cost - total cost + [3] costpp - cost per patient + [4] first_seen - first intervention date + [5] last_seen - last intervention date + [6] first_seen_parent - earliest date in parent group + [7] last_seen_parent - latest date in parent group + [8] average_spacing - dosing information string + [9] cost_pp_pa - cost per patient per annum Returns: Plotly Figure object ready for rx.plotly() component @@ -1238,9 +1248,32 @@ class AppState(rx.State): ids = [d.get("ids", "") for d in self.chart_data] labels = [d.get("labels", "") for d in self.chart_data] values = [d.get("value", 0) for d in self.chart_data] - costs = [d.get("cost", 0.0) for d in self.chart_data] colours = [d.get("colour", 0.0) for d in self.chart_data] + # Extract full 10-field customdata + costs = [d.get("cost", 0.0) for d in self.chart_data] + costpp = [d.get("costpp", 0.0) for d in self.chart_data] + first_seen = [d.get("first_seen", "N/A") or "N/A" for d in self.chart_data] + last_seen = [d.get("last_seen", "N/A") or "N/A" for d in self.chart_data] + first_seen_parent = [d.get("first_seen_parent", "N/A") or "N/A" for d in self.chart_data] + last_seen_parent = [d.get("last_seen_parent", "N/A") or "N/A" for d in self.chart_data] + average_spacing = [d.get("average_spacing", "") or "" for d in self.chart_data] + cost_pp_pa = [d.get("cost_pp_pa", 0.0) or 0.0 for d in self.chart_data] + + # Build customdata as list of tuples (10 fields) + customdata = list(zip( + values, # [0] + colours, # [1] + costs, # [2] + costpp, # [3] + first_seen, # [4] + last_seen, # [5] + first_seen_parent, # [6] + last_seen_parent, # [7] + average_spacing, # [8] + cost_pp_pa, # [9] + )) + # NHS-inspired blue gradient colorscale (from design system) # Heritage Blue → Primary Blue → Vibrant Blue → Sky Blue → Pale Blue colorscale = [ @@ -1251,7 +1284,7 @@ class AppState(rx.State): [1.0, "#E3F2FD"], # Pale Blue ] - # Create the icicle chart + # Create the icicle chart with full customdata structure fig = go.Figure( go.Icicle( labels=labels, @@ -1265,15 +1298,29 @@ class AppState(rx.State): line=dict(width=1, color="#FFFFFF"), ), maxdepth=3, - # Custom data for hover template - customdata=list(zip(values, colours, costs)), - # Text shown on chart segments - texttemplate="%{label}
%{value:,} patients", - # Hover text with full details + customdata=customdata, + # Text shown on chart segments - includes treatment statistics + texttemplate=( + "%{label} " + "
Total patients: %{customdata[0]} (including children/further treatments)" + "
First seen: %{customdata[4]}" + "
Last seen (including further treatments): %{customdata[7]}" + "
Average treatment duration: %{customdata[8]}" + "
Total cost: £%{customdata[2]:.3~s}" + "
Average cost per patient: £%{customdata[3]:.3~s}" + "
Average cost per patient per annum: £%{customdata[9]:.3~s}" + ), + # Hover text with full details matching original chart hovertemplate=( - "%{label}
" - "Patients: %{customdata[0]:,} (%{customdata[1]:.1%} of parent)
" - "Total Cost: £%{customdata[2]:,.0f}" + "%{label}" + "
Total patients: %{customdata[0]} - %{customdata[1]:.3p} of patients in level" + "
Total cost: £%{customdata[2]:.3~s}" + "
Average cost per patient: £%{customdata[3]:.3~s}" + "
Average cost per patient per annum: £%{customdata[9]:.3~s}" + "
First seen: %{customdata[4]}" + "
Last seen (including further treatments): %{customdata[7]}" + "
Average treatment duration:" + "%{customdata[8]}" "" ), textfont=dict( @@ -1301,7 +1348,7 @@ class AppState(rx.State): bordercolor="#CBD5E1", # Slate 300 font=dict( family="Inter, system-ui, sans-serif", - size=13, + size=14, color="#1E293B", # Slate 900 ), ),