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
|
### A.4 Fix trust comparison color differentiation
|
||||||
- [x] In `create_trust_duration_figure()`: replace `nhs_colours` list with `TRUST_PALETTE` (done in A.3)
|
- [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
|
- [x] 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`
|
- [x] Update `tc_cost_waterfall` callback in `dash_app/callbacks/trust_comparison.py` to pass `is_trust_comparison=True`
|
||||||
- [ ] Fix `_dosing_by_drug()` blue→blue interpolation: replace with `plotly.colors.sample_colorscale("Viridis", ...)` for meaningful gradient
|
- [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] 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)
|
- [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
|
- **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
|
# Reuse existing waterfall figure — map trust_name to directory key
|
||||||
mapped = [{"directory": d["trust_name"], "patients": d["patients"],
|
mapped = [{"directory": d["trust_name"], "patients": d["patients"],
|
||||||
"total_cost": d["total_cost"], "cost_pp": d["cost_pp"]} for d in data]
|
"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
|
# 3. Dosing — drug dosing intervals by trust
|
||||||
@app.callback(
|
@app.callback(
|
||||||
|
|||||||
@@ -632,6 +632,7 @@ def create_cost_effectiveness_figure(
|
|||||||
def create_cost_waterfall_figure(
|
def create_cost_waterfall_figure(
|
||||||
data: list[dict],
|
data: list[dict],
|
||||||
title: str = "",
|
title: str = "",
|
||||||
|
is_trust_comparison: bool = False,
|
||||||
) -> go.Figure:
|
) -> go.Figure:
|
||||||
"""Create waterfall chart showing cost per patient by directorate/indication.
|
"""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]
|
patients_list = [d["patients"] for d in data]
|
||||||
total_costs = [d["total_cost"] for d in data]
|
total_costs = [d["total_cost"] for d in data]
|
||||||
|
|
||||||
# NHS colour palette for bars
|
palette = TRUST_PALETTE if is_trust_comparison else DRUG_PALETTE
|
||||||
nhs_colours = [
|
bar_colours = [palette[i % len(palette)] for i in range(len(data))]
|
||||||
"#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))]
|
|
||||||
|
|
||||||
hover_texts = []
|
hover_texts = []
|
||||||
for d in data:
|
for d in data:
|
||||||
@@ -699,7 +693,7 @@ def create_cost_waterfall_figure(
|
|||||||
text=f"n={pts:,}",
|
text=f"n={pts:,}",
|
||||||
showarrow=False,
|
showarrow=False,
|
||||||
yshift=-18,
|
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
|
# Grand total line
|
||||||
@@ -715,7 +709,7 @@ def create_cost_waterfall_figure(
|
|||||||
annotation_text=f"Weighted avg: £{weighted_avg:,.0f}",
|
annotation_text=f"Weighted avg: £{weighted_avg:,.0f}",
|
||||||
annotation_position="top right",
|
annotation_position="top right",
|
||||||
annotation_font=dict(
|
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"
|
else "Cost per Patient by Directorate"
|
||||||
)
|
)
|
||||||
|
|
||||||
fig.update_layout(
|
layout = _base_layout(display_title)
|
||||||
title=dict(
|
layout.update(
|
||||||
text=display_title,
|
|
||||||
font=dict(
|
|
||||||
family="Source Sans 3, system-ui, sans-serif",
|
|
||||||
size=18,
|
|
||||||
color="#1E293B",
|
|
||||||
),
|
|
||||||
x=0.5,
|
|
||||||
xanchor="center",
|
|
||||||
),
|
|
||||||
xaxis=dict(
|
xaxis=dict(
|
||||||
title="",
|
title="",
|
||||||
tickangle=-45 if len(data) > 6 else 0,
|
tickangle=-45 if len(data) > 6 else 0,
|
||||||
@@ -745,30 +730,16 @@ def create_cost_waterfall_figure(
|
|||||||
title="£ per patient",
|
title="£ per patient",
|
||||||
tickprefix="£",
|
tickprefix="£",
|
||||||
tickformat=",",
|
tickformat=",",
|
||||||
gridcolor="#E2E8F0",
|
gridcolor=GRID_COLOR,
|
||||||
zeroline=True,
|
zeroline=True,
|
||||||
zerolinecolor="#CBD5E1",
|
zerolinecolor="#CBD5E1",
|
||||||
),
|
),
|
||||||
margin=dict(t=60, l=8, r=24, b=40),
|
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,
|
showlegend=False,
|
||||||
hoverlabel=dict(
|
height=500,
|
||||||
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),
|
|
||||||
bargap=0.25,
|
bargap=0.25,
|
||||||
)
|
)
|
||||||
|
fig.update_layout(**layout)
|
||||||
|
|
||||||
return fig
|
return fig
|
||||||
|
|
||||||
@@ -1005,16 +976,12 @@ def _dosing_by_drug(data: list[dict], colours: list[str]) -> go.Figure:
|
|||||||
f"Patients: {tp:,}"
|
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
|
max_interval = max(intervals) if intervals else 1
|
||||||
bar_colours = []
|
ratios = [iv / max_interval if max_interval > 0 else 0 for iv in intervals]
|
||||||
for iv in intervals:
|
bar_colours = pc.sample_colorscale("Viridis", ratios)
|
||||||
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})")
|
|
||||||
|
|
||||||
fig = go.Figure()
|
fig = go.Figure()
|
||||||
fig.add_trace(go.Bar(
|
fig.add_trace(go.Bar(
|
||||||
|
|||||||
Reference in New Issue
Block a user