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.
This commit is contained in:
Andrew Charlwood
2026-02-05 00:30:22 +00:00
parent fc3b3525c6
commit ced994f93f
2 changed files with 67 additions and 19 deletions
+62 -15
View File
@@ -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="<b>%{label}</b><br>%{value:,} patients",
# Hover text with full details
customdata=customdata,
# Text shown on chart segments - includes treatment statistics
texttemplate=(
"<b>%{label}</b> "
"<br><b>Total patients:</b> %{customdata[0]} (including children/further treatments)"
"<br><b>First seen:</b> %{customdata[4]}"
"<br><b>Last seen (including further treatments):</b> %{customdata[7]}"
"<br><b>Average treatment duration:</b> %{customdata[8]}"
"<br><b>Total cost:</b> £%{customdata[2]:.3~s}"
"<br><b>Average cost per patient:</b> £%{customdata[3]:.3~s}"
"<br><b>Average cost per patient per annum:</b> £%{customdata[9]:.3~s}"
),
# Hover text with full details matching original chart
hovertemplate=(
"<b>%{label}</b><br>"
"Patients: %{customdata[0]:,} (%{customdata[1]:.1%} of parent)<br>"
"Total Cost: £%{customdata[2]:,.0f}"
"<b>%{label}</b>"
"<br><b>Total patients:</b> %{customdata[0]} - %{customdata[1]:.3p} of patients in level"
"<br><b>Total cost:</b> £%{customdata[2]:.3~s}"
"<br><b>Average cost per patient:</b> £%{customdata[3]:.3~s}"
"<br><b>Average cost per patient per annum:</b> £%{customdata[9]:.3~s}"
"<br><b>First seen:</b> %{customdata[4]}"
"<br><b>Last seen (including further treatments):</b> %{customdata[7]}"
"<br><b>Average treatment duration:</b>"
"%{customdata[8]}"
"<extra></extra>"
),
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
),
),