Hero gauges: switch to horizontal thermometer bars (mobile-friendly)
Browse filesThe three radial dial gauges packed badly on portrait phones β they
shrank to thumbnail size with unreadable needles and values. Replace
with three stacked horizontal bars on a shared 20-100Β°F scale:
- π‘ Ecowitt (now) βββββββββββββββ 63.5Β°F
- π€ Toto (next hr) βββββββββββββββ 64.3Β°F (+0.8)
- π NWS (next hr) βββββββββββββββ 61.0Β°F (-2.5)
Same cool/warm background bands as before so the eye still reads
'where on the temperature spectrum'. Bar color matches each source's
chart trace. Delta vs current temperature annotated in muted gray on
the right of each forecast bar. Bars take the full width of the
container so they stay legible at any breakpoint.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- src/weather_ui.py +63 -36
|
@@ -186,46 +186,73 @@ def hero_gauges(
|
|
| 186 |
nws_next: float | None,
|
| 187 |
temp_range: tuple[float, float] = (20.0, 100.0),
|
| 188 |
) -> go.Figure:
|
| 189 |
-
"""Three
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
{"range": [80, 100], "color": "rgba(214,39,40,0.18)"},
|
| 197 |
]
|
| 198 |
-
|
| 199 |
-
fig =
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
steps=cool_to_warm,
|
| 214 |
-
threshold=dict(line=dict(color=bar_color, width=4), value=value or 0),
|
| 215 |
-
),
|
| 216 |
-
delta=(
|
| 217 |
-
dict(reference=cur_temp, suffix=" Β°F", increasing={"color": "#d62728"}, decreasing={"color": "#1f77b4"})
|
| 218 |
-
if with_delta else None
|
| 219 |
-
),
|
| 220 |
)
|
| 221 |
-
return ind
|
| 222 |
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
fig.update_layout(
|
| 227 |
-
height=
|
| 228 |
-
margin=dict(l=
|
|
|
|
|
|
|
| 229 |
paper_bgcolor="rgba(0,0,0,0)",
|
| 230 |
)
|
| 231 |
return fig
|
|
|
|
| 186 |
nws_next: float | None,
|
| 187 |
temp_range: tuple[float, float] = (20.0, 100.0),
|
| 188 |
) -> go.Figure:
|
| 189 |
+
"""Three horizontal bar 'thermometers' stacked vertically β readable
|
| 190 |
+
on mobile portrait without squishing. Cool/warm background bands
|
| 191 |
+
give a sense of where on the temperature scale each value sits."""
|
| 192 |
+
rows = [
|
| 193 |
+
("π‘ Ecowitt (now)", cur_temp, "#222", None),
|
| 194 |
+
("π€ Toto (next hr)", toto_next, "#1f77b4", cur_temp),
|
| 195 |
+
("π NWS (next hr)", nws_next, "#d62728", cur_temp),
|
|
|
|
| 196 |
]
|
| 197 |
+
|
| 198 |
+
fig = go.Figure()
|
| 199 |
+
lo, hi = temp_range
|
| 200 |
+
# Background shading: cooler on the left, warmer on the right.
|
| 201 |
+
for x0, x1, color in [
|
| 202 |
+
(lo, lo + (hi - lo) * 0.25, "rgba(31,119,180,0.18)"),
|
| 203 |
+
(lo + (hi - lo) * 0.25, lo + (hi - lo) * 0.50, "rgba(31,119,180,0.08)"),
|
| 204 |
+
(lo + (hi - lo) * 0.50, lo + (hi - lo) * 0.75, "rgba(214,39,40,0.08)"),
|
| 205 |
+
(lo + (hi - lo) * 0.75, hi, "rgba(214,39,40,0.18)"),
|
| 206 |
+
]:
|
| 207 |
+
fig.add_shape(
|
| 208 |
+
type="rect",
|
| 209 |
+
x0=x0, x1=x1, y0=-0.5, y1=len(rows) - 0.5,
|
| 210 |
+
fillcolor=color, line=dict(width=0),
|
| 211 |
+
layer="below",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
)
|
|
|
|
| 213 |
|
| 214 |
+
y_labels = [r[0] for r in rows]
|
| 215 |
+
for label, value, color, ref in rows:
|
| 216 |
+
if value is None or (isinstance(value, float) and value != value):
|
| 217 |
+
# No data β skip the bar but keep the row label by drawing 0-length.
|
| 218 |
+
fig.add_trace(go.Bar(
|
| 219 |
+
y=[label], x=[lo], orientation="h",
|
| 220 |
+
marker_color="rgba(0,0,0,0)",
|
| 221 |
+
text=["β"], textposition="outside",
|
| 222 |
+
textfont=dict(size=14, color="#888"),
|
| 223 |
+
showlegend=False, hoverinfo="skip",
|
| 224 |
+
))
|
| 225 |
+
continue
|
| 226 |
+
suffix = ""
|
| 227 |
+
if ref is not None:
|
| 228 |
+
d = value - ref
|
| 229 |
+
sign = "+" if d >= 0 else ""
|
| 230 |
+
suffix = f" <span style='color:#888'>({sign}{d:.1f})</span>"
|
| 231 |
+
fig.add_trace(go.Bar(
|
| 232 |
+
y=[label], x=[value - lo], base=[lo], orientation="h",
|
| 233 |
+
marker=dict(color=color, line=dict(color=color, width=0)),
|
| 234 |
+
text=[f"<b>{value:.1f}Β°F</b>{suffix}"],
|
| 235 |
+
textposition="outside",
|
| 236 |
+
textfont=dict(size=14),
|
| 237 |
+
cliponaxis=False,
|
| 238 |
+
showlegend=False,
|
| 239 |
+
hovertemplate=f"{label}: %{{x:.1f}}Β°F<extra></extra>",
|
| 240 |
+
))
|
| 241 |
+
|
| 242 |
+
fig.update_xaxes(
|
| 243 |
+
range=[lo, hi], title_text="Β°F",
|
| 244 |
+
showgrid=True, gridcolor="rgba(0,0,0,0.08)",
|
| 245 |
+
zeroline=False,
|
| 246 |
+
)
|
| 247 |
+
fig.update_yaxes(
|
| 248 |
+
categoryorder="array", categoryarray=list(reversed(y_labels)),
|
| 249 |
+
showgrid=False,
|
| 250 |
+
)
|
| 251 |
fig.update_layout(
|
| 252 |
+
height=240,
|
| 253 |
+
margin=dict(l=130, r=90, t=20, b=40),
|
| 254 |
+
bargap=0.35,
|
| 255 |
+
plot_bgcolor="rgba(0,0,0,0)",
|
| 256 |
paper_bgcolor="rgba(0,0,0,0)",
|
| 257 |
)
|
| 258 |
return fig
|