feat: add KPI update callback with formatted patient/drug/cost display (Task 3.3)

This commit is contained in:
Andrew Charlwood
2026-02-06 13:38:11 +00:00
parent f5486fc79e
commit 9c971c083b
3 changed files with 44 additions and 1 deletions
+1 -1
View File
@@ -179,7 +179,7 @@ Drawer selection → update_drug_selection → app-state store → load_pathway_
- **Checkpoint**: Changing date filter updates chart-data store with new pathway nodes ✓
### 3.3 KPI update callback
- [ ] Create `dash_app/callbacks/kpi.py`:
- [x] Create `dash_app/callbacks/kpi.py`:
- `update_kpis` callback: Input=`chart-data` store, Output=KPI card values (4 outputs)
- Extracts `unique_patients`, `total_drugs`, `total_cost` from chart-data
- Formats numbers: patients with commas, cost as "£XXX.XM", drugs as plain number
+2
View File
@@ -5,6 +5,8 @@ def register_callbacks(app):
"""Register all Dash callbacks with the app instance."""
from dash_app.callbacks.filters import register_filter_callbacks
from dash_app.callbacks.chart import register_chart_callbacks
from dash_app.callbacks.kpi import register_kpi_callbacks
register_filter_callbacks(app)
register_chart_callbacks(app)
register_kpi_callbacks(app)
+41
View File
@@ -0,0 +1,41 @@
"""Callback for updating KPI card values from chart-data store."""
from dash import Input, Output, no_update
def _format_cost(cost):
"""Format cost as £X.XM or £X.XK."""
if cost >= 1_000_000:
return f"\u00a3{cost / 1_000_000:.1f}M"
if cost >= 1_000:
return f"\u00a3{cost / 1_000:.1f}K"
return f"\u00a3{cost:.0f}"
def register_kpi_callbacks(app):
"""Register KPI update callback."""
@app.callback(
Output("kpi-patients", "children"),
Output("kpi-drugs", "children"),
Output("kpi-cost", "children"),
Output("kpi-match", "children"),
Input("chart-data", "data"),
Input("app-state", "data"),
)
def update_kpis(chart_data, app_state):
"""Update KPI card values when chart-data changes."""
if not chart_data:
return no_update, no_update, no_update, no_update
patients = chart_data.get("unique_patients", 0)
drugs = chart_data.get("total_drugs", 0)
cost = chart_data.get("total_cost", 0.0)
patients_str = f"{patients:,}" if patients else "\u2014"
drugs_str = str(drugs) if drugs else "\u2014"
cost_str = _format_cost(cost) if cost else "\u2014"
chart_type = (app_state or {}).get("chart_type", "directory")
match_str = "~93%" if chart_type == "indication" else "\u2014"
return patients_str, drugs_str, cost_str, match_str