fix: trust palette for cost waterfall + Viridis dosing gradient (Task A.4)
This commit is contained in:
@@ -79,9 +79,9 @@ Comprehensive review and improvement of all Plotly charts in the Dash dashboard.
|
||||
|
||||
### A.4 Fix trust comparison color differentiation
|
||||
- [x] In `create_trust_duration_figure()`: replace `nhs_colours` list with `TRUST_PALETTE` (done in A.3)
|
||||
- [ ] Add `is_trust_comparison=False` param to `create_cost_waterfall_figure()` — use `TRUST_PALETTE` when True
|
||||
- [ ] Update `tc_cost_waterfall` callback in `dash_app/callbacks/trust_comparison.py` (~L165) to pass `is_trust_comparison=True`
|
||||
- [ ] Fix `_dosing_by_drug()` blue→blue interpolation: replace with `plotly.colors.sample_colorscale("Viridis", ...)` for meaningful gradient
|
||||
- [x] Add `is_trust_comparison=False` param to `create_cost_waterfall_figure()` — use `TRUST_PALETTE` when True
|
||||
- [x] Update `tc_cost_waterfall` callback in `dash_app/callbacks/trust_comparison.py` to pass `is_trust_comparison=True`
|
||||
- [x] Fix `_dosing_by_drug()` blue→blue interpolation: replaced with `plotly.colors.sample_colorscale("Viridis", ...)` for meaningful gradient
|
||||
- [x] Replace `nhs_colours` in `create_trust_market_share_figure()` with `DRUG_PALETTE` for drug traces (done in A.3)
|
||||
- [x] Apply `_base_layout()` to all affected functions (done in A.3 for trust_market_share and trust_duration)
|
||||
- **Checkpoint**: Trust Comparison charts have 7 visually distinct trust colors; dosing has meaningful gradient
|
||||
|
||||
@@ -164,7 +164,7 @@ def register_trust_comparison_callbacks(app):
|
||||
# Reuse existing waterfall figure — map trust_name to directory key
|
||||
mapped = [{"directory": d["trust_name"], "patients": d["patients"],
|
||||
"total_cost": d["total_cost"], "cost_pp": d["cost_pp"]} for d in data]
|
||||
return create_cost_waterfall_figure(mapped, _tc_title(app_state))
|
||||
return create_cost_waterfall_figure(mapped, _tc_title(app_state), is_trust_comparison=True)
|
||||
|
||||
# 3. Dosing — drug dosing intervals by trust
|
||||
@app.callback(
|
||||
|
||||
@@ -632,6 +632,7 @@ def create_cost_effectiveness_figure(
|
||||
def create_cost_waterfall_figure(
|
||||
data: list[dict],
|
||||
title: str = "",
|
||||
is_trust_comparison: bool = False,
|
||||
) -> go.Figure:
|
||||
"""Create waterfall chart showing cost per patient by directorate/indication.
|
||||
|
||||
@@ -652,15 +653,8 @@ def create_cost_waterfall_figure(
|
||||
patients_list = [d["patients"] for d in data]
|
||||
total_costs = [d["total_cost"] for d in data]
|
||||
|
||||
# NHS colour palette for bars
|
||||
nhs_colours = [
|
||||
"#005EB8", "#003087", "#41B6E6", "#0066CC", "#1E88E5",
|
||||
"#4FC3F7", "#009639", "#ED8B00", "#768692", "#425563",
|
||||
"#DA291C", "#7C2855",
|
||||
]
|
||||
|
||||
# Assign colours cycling through palette
|
||||
bar_colours = [nhs_colours[i % len(nhs_colours)] for i in range(len(data))]
|
||||
palette = TRUST_PALETTE if is_trust_comparison else DRUG_PALETTE
|
||||
bar_colours = [palette[i % len(palette)] for i in range(len(data))]
|
||||
|
||||
hover_texts = []
|
||||
for d in data:
|
||||
@@ -699,7 +693,7 @@ def create_cost_waterfall_figure(
|
||||
text=f"n={pts:,}",
|
||||
showarrow=False,
|
||||
yshift=-18,
|
||||
font=dict(size=10, color="#768692", family="Source Sans 3"),
|
||||
font=dict(size=10, color=ANNOTATION_COLOR, family=CHART_FONT_FAMILY),
|
||||
)
|
||||
|
||||
# Grand total line
|
||||
@@ -715,7 +709,7 @@ def create_cost_waterfall_figure(
|
||||
annotation_text=f"Weighted avg: £{weighted_avg:,.0f}",
|
||||
annotation_position="top right",
|
||||
annotation_font=dict(
|
||||
size=11, color="#DA291C", family="Source Sans 3"
|
||||
size=11, color="#DA291C", family=CHART_FONT_FAMILY
|
||||
),
|
||||
)
|
||||
|
||||
@@ -724,17 +718,8 @@ def create_cost_waterfall_figure(
|
||||
else "Cost per Patient by Directorate"
|
||||
)
|
||||
|
||||
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="",
|
||||
tickangle=-45 if len(data) > 6 else 0,
|
||||
@@ -745,30 +730,16 @@ def create_cost_waterfall_figure(
|
||||
title="£ per patient",
|
||||
tickprefix="£",
|
||||
tickformat=",",
|
||||
gridcolor="#E2E8F0",
|
||||
gridcolor=GRID_COLOR,
|
||||
zeroline=True,
|
||||
zerolinecolor="#CBD5E1",
|
||||
),
|
||||
margin=dict(t=60, l=8, r=24, b=40),
|
||||
paper_bgcolor="rgba(0,0,0,0)",
|
||||
plot_bgcolor="rgba(0,0,0,0)",
|
||||
autosize=True,
|
||||
showlegend=False,
|
||||
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, 500),
|
||||
height=500,
|
||||
bargap=0.25,
|
||||
)
|
||||
fig.update_layout(**layout)
|
||||
|
||||
return fig
|
||||
|
||||
@@ -1005,16 +976,12 @@ def _dosing_by_drug(data: list[dict], colours: list[str]) -> go.Figure:
|
||||
f"Patients: {tp:,}"
|
||||
)
|
||||
|
||||
# Colour bars by interval: lower = more frequent dosing = NHS blue, higher = lighter
|
||||
# Colour bars by interval: lower = more frequent dosing, higher = less frequent
|
||||
# Use Viridis colorscale for meaningful gradient (replaces blue→blue interpolation)
|
||||
import plotly.colors as pc
|
||||
max_interval = max(intervals) if intervals else 1
|
||||
bar_colours = []
|
||||
for iv in intervals:
|
||||
ratio = iv / max_interval if max_interval > 0 else 0
|
||||
# Interpolate NHS blue (#005EB8) to light blue (#41B6E6)
|
||||
r = int(0x00 + (0x41 - 0x00) * ratio)
|
||||
g = int(0x5E + (0xB6 - 0x5E) * ratio)
|
||||
b = int(0xB8 + (0xE6 - 0xB8) * ratio)
|
||||
bar_colours.append(f"rgb({r},{g},{b})")
|
||||
ratios = [iv / max_interval if max_interval > 0 else 0 for iv in intervals]
|
||||
bar_colours = pc.sample_colorscale("Viridis", ratios)
|
||||
|
||||
fig = go.Figure()
|
||||
fig.add_trace(go.Bar(
|
||||
|
||||
Reference in New Issue
Block a user