feat: Trends drill-down — click directorate to see drug-level trends (Task E.4)
This commit is contained in:
@@ -78,12 +78,15 @@ def register_filter_callbacks(app):
|
||||
Input("nav-trends", "n_clicks"),
|
||||
Input({"type": "tc-selector", "index": ALL}, "n_clicks"),
|
||||
Input("tc-back-btn", "n_clicks"),
|
||||
Input("trends-overview-chart", "clickData"),
|
||||
Input("trends-back-btn", "n_clicks"),
|
||||
State("app-state", "data"),
|
||||
)
|
||||
def update_app_state(
|
||||
_dir_clicks, _ind_clicks, initiated, last_seen, selected_drugs,
|
||||
selected_trusts, _nav_pp_clicks, _nav_tc_clicks, _nav_trends_clicks,
|
||||
_tc_selector_clicks, _tc_back_clicks, current_state
|
||||
_tc_selector_clicks, _tc_back_clicks, trends_click_data,
|
||||
_trends_back_clicks, current_state
|
||||
):
|
||||
"""Update app-state when any filter, nav, or TC selector changes."""
|
||||
if not current_state:
|
||||
@@ -134,6 +137,21 @@ def register_filter_callbacks(app):
|
||||
if chart_type != prev_chart_type and selected_comparison_directorate is not None:
|
||||
selected_comparison_directorate = None
|
||||
|
||||
# Trends directorate drill-down
|
||||
selected_trends_directorate = current_state.get("selected_trends_directorate")
|
||||
|
||||
if triggered_id == "trends-overview-chart" and trends_click_data:
|
||||
points = trends_click_data.get("points", [])
|
||||
if points:
|
||||
selected_trends_directorate = points[0].get("customdata")
|
||||
|
||||
if triggered_id == "trends-back-btn":
|
||||
selected_trends_directorate = None
|
||||
|
||||
# If chart type changed while trends directorate is selected, return to landing
|
||||
if chart_type != prev_chart_type and selected_trends_directorate is not None:
|
||||
selected_trends_directorate = None
|
||||
|
||||
# Compute date_filter_id from dropdown values
|
||||
date_filter_id = f"{initiated}_{last_seen}"
|
||||
|
||||
@@ -148,6 +166,7 @@ def register_filter_callbacks(app):
|
||||
"selected_trusts": selected_trusts or [],
|
||||
"active_view": active_view,
|
||||
"selected_comparison_directorate": selected_comparison_directorate,
|
||||
"selected_trends_directorate": selected_trends_directorate,
|
||||
}
|
||||
|
||||
# Toggle pill CSS classes
|
||||
|
||||
@@ -92,3 +92,49 @@ def register_trends_callbacks(app):
|
||||
title = f"Directorate Trends \u2014 {metric_labels.get(metric, 'Patients')}"
|
||||
|
||||
return create_trend_figure(data, title, metric)
|
||||
|
||||
# --- Drug detail chart (drill-down) ---
|
||||
@app.callback(
|
||||
Output("trends-detail-chart", "figure"),
|
||||
Input("app-state", "data"),
|
||||
Input("trends-detail-metric-toggle", "value"),
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
def render_trends_detail(app_state, metric):
|
||||
"""Render drug-level trends for the selected directorate."""
|
||||
if not app_state:
|
||||
return no_update
|
||||
|
||||
active_view = app_state.get("active_view", "")
|
||||
if active_view != "trends":
|
||||
return no_update
|
||||
|
||||
selected = app_state.get("selected_trends_directorate")
|
||||
if not selected:
|
||||
return no_update
|
||||
|
||||
metric = metric or "patients"
|
||||
|
||||
from dash_app.data.queries import get_trend_data
|
||||
from visualization.plotly_generator import create_trend_figure
|
||||
|
||||
try:
|
||||
data = get_trend_data(
|
||||
metric=metric,
|
||||
directory=selected,
|
||||
group_by="drug",
|
||||
)
|
||||
except Exception:
|
||||
return _trends_empty("Failed to load trend data.")
|
||||
|
||||
if not data:
|
||||
return _trends_empty("No trend data for this directorate.")
|
||||
|
||||
metric_labels = {
|
||||
"patients": "Patients",
|
||||
"total_cost": "Cost per Patient",
|
||||
"cost_pp_pa": "Cost per Patient p.a.",
|
||||
}
|
||||
title = f"{selected} \u2014 {metric_labels.get(metric, 'Patients')}"
|
||||
|
||||
return create_trend_figure(data, title, metric)
|
||||
|
||||
Reference in New Issue
Block a user