diff --git a/IMPLEMENTATION_PLAN.md b/IMPLEMENTATION_PLAN.md index 08847d7..09a5e08 100644 --- a/IMPLEMENTATION_PLAN.md +++ b/IMPLEMENTATION_PLAN.md @@ -91,12 +91,13 @@ Comprehensive review and improvement of all Plotly charts in the Dash dashboard. ## Phase B: Visual Polish ### B.1 Fix title inconsistencies across all charts -- [ ] Sankey (~L817): title color `"#003087"` → `CHART_TITLE_COLOR` -- [ ] Dosing (~L885): title color `"#003087"` → `CHART_TITLE_COLOR` -- [ ] Patient Pathways heatmap (~L1300): title color `"#003087"` → `CHART_TITLE_COLOR` -- [ ] Duration (~L1449): title color `"#003087"` → `CHART_TITLE_COLOR` -- [ ] All Trust Comparison functions: title `size=16` → `CHART_TITLE_SIZE` (18) -- [ ] Apply `_base_layout()` to all remaining chart functions not yet converted +- [x] Sankey: replaced local nhs_colours with DRUG_PALETTE, title color `"#003087"` → `CHART_TITLE_COLOR` via `_base_layout()` +- [x] Dosing: already converted in A.3 — uses `_base_layout()` with CHART_TITLE_COLOR +- [x] Patient Pathways heatmap: already converted in A.2 — uses `_base_layout()` with CHART_TITLE_COLOR +- [x] Duration: title color `"#003087"` → `CHART_TITLE_COLOR`, fixed l=200→l=8+automargin, used constants for annotations +- [x] All Trust Comparison functions: already use `_base_layout()` (A.2-A.4), title size=18 via CHART_TITLE_SIZE +- [x] Applied `_base_layout()` to all remaining chart functions: Sankey, Cost Effectiveness, Duration +- [x] Cost Effectiveness: replaced 38-line manual layout with `_base_layout()`, hardcoded colors/fonts → constants - **Checkpoint**: All chart titles use consistent font, size, and color ### B.2 Cost effectiveness smooth gradient diff --git a/src/visualization/plotly_generator.py b/src/visualization/plotly_generator.py index b76e429..02956cd 100644 --- a/src/visualization/plotly_generator.py +++ b/src/visualization/plotly_generator.py @@ -579,26 +579,17 @@ def create_cost_effectiveness_figure( showarrow=False, xanchor="left", xshift=10, - font=dict(size=10, color="#768692", family="Source Sans 3"), + font=dict(size=10, color=ANNOTATION_COLOR, family=CHART_FONT_FAMILY), ) annotation_count += 1 - fig.update_layout( - title=dict( - text=display_title, - font=dict( - family="Source Sans 3, system-ui, sans-serif", - size=18, - color="#1E293B", - ), - x=0.5, - xanchor="center", - ), + layout = _base_layout(display_title) + layout.update( xaxis=dict( title="£ per patient per annum", tickprefix="£", tickformat=",", - gridcolor="#E2E8F0", + gridcolor=GRID_COLOR, zeroline=True, zerolinecolor="#CBD5E1", ), @@ -608,23 +599,9 @@ def create_cost_effectiveness_figure( tickfont=dict(size=11), ), margin=dict(t=50, l=8, r=24, b=40), - paper_bgcolor="rgba(0,0,0,0)", - plot_bgcolor="rgba(0,0,0,0)", - autosize=True, - hoverlabel=dict( - bgcolor="#FFFFFF", - bordercolor="#CBD5E1", - font=dict( - family="Source Sans 3, system-ui, sans-serif", - size=13, - color="#1E293B", - ), - ), - font=dict( - family="Source Sans 3, system-ui, sans-serif", - ), height=max(450, len(filtered) * 28 + 150), ) + fig.update_layout(**layout) return fig @@ -767,13 +744,6 @@ def create_sankey_figure( if not nodes or not links: return go.Figure() - # NHS colour palette — one colour per unique base drug name - nhs_colours = [ - "#005EB8", "#003087", "#41B6E6", "#0066CC", "#1E88E5", - "#4FC3F7", "#009639", "#ED8B00", "#768692", "#AE2573", - "#8A1538", "#330072", "#DA291C", "#00A499", "#425563", - ] - # Extract base drug name (strip ordinal suffix) for colour consistency def base_drug(name: str) -> str: return re.sub(r"\s*\(\d+(?:st|nd|rd|th)\)\s*$", "", name) @@ -783,7 +753,7 @@ def create_sankey_figure( b = base_drug(n["name"]) if b not in unique_bases: unique_bases.append(b) - base_colour_map = {b: nhs_colours[i % len(nhs_colours)] for i, b in enumerate(unique_bases)} + base_colour_map = {b: DRUG_PALETTE[i % len(DRUG_PALETTE)] for i, b in enumerate(unique_bases)} # Node colours — same drug gets same colour regardless of treatment line node_colours = [base_colour_map[base_drug(n["name"])] for n in nodes] @@ -851,26 +821,13 @@ def create_sankey_figure( if title: chart_title = f"{chart_title} — {title}" - fig.update_layout( - title=dict( - text=chart_title, - font=dict( - family="Source Sans 3, system-ui, sans-serif", - size=18, - color="#003087", - ), - x=0.5, - xanchor="center", - ), - font=dict( - family="Source Sans 3, system-ui, sans-serif", - size=12, - ), - paper_bgcolor="rgba(0,0,0,0)", - plot_bgcolor="rgba(0,0,0,0)", + layout = _base_layout(chart_title) + layout.update( + font=dict(family=CHART_FONT_FAMILY, size=12), margin=dict(t=60, l=30, r=30, b=30), height=max(500, len(unique_bases) * 35 + 200), ) + fig.update_layout(**layout) return fig @@ -1453,27 +1410,18 @@ def create_duration_figure( text=f"n={pts:,}", showarrow=False, xshift=45, - font=dict(size=9, color="#768692", family="Source Sans 3"), + font=dict(size=9, color=ANNOTATION_COLOR, family=CHART_FONT_FAMILY), ) chart_title = "Treatment Duration by Drug" if title: - chart_title += f"
{title}" + chart_title += f"
{title}" n_bars = len(data) fig_height = max(400, 40 + n_bars * 28) - fig.update_layout( - title=dict( - text=chart_title, - font=dict( - family="Source Sans 3, system-ui, sans-serif", - size=18, - color="#003087", - ), - x=0.5, - xanchor="center", - ), + layout = _base_layout(chart_title) + layout.update( xaxis=dict( title="Average Duration (days)", titlefont=dict(size=13, color="#425563"), @@ -1485,15 +1433,14 @@ def create_duration_figure( yaxis=dict( title="", tickfont=dict(size=11, color="#425563"), + automargin=True, autorange="reversed", ), - plot_bgcolor="rgba(0,0,0,0)", - paper_bgcolor="rgba(0,0,0,0)", - font=dict(family="Source Sans 3, system-ui, sans-serif"), - margin=dict(t=60, l=200, r=80, b=50), + margin=dict(t=60, l=8, r=80, b=50), height=fig_height, showlegend=False, ) + fig.update_layout(**layout) return fig