Records: show longest dry streak instead of record-low precipitation (#105)
Record-low rainfall is meaningless (always ~0), so the precip row's low side now shows the longest run of consecutive days without measurable rain and the date that dry spell began (grading.longest_dry_streak), keeping the wettest day on the high side. A footnote explains the substitution.
This commit is contained in:
parent
0e16ad2a93
commit
5f380bcadd
3 changed files with 36 additions and 1 deletions
10
content.py
10
content.py
|
|
@ -347,10 +347,18 @@ def _records_context(request, city, history) -> dict:
|
||||||
r = rec.get(key)
|
r = rec.get(key)
|
||||||
if not r:
|
if not r:
|
||||||
continue
|
continue
|
||||||
|
if key == "precip":
|
||||||
|
# "Record low" rain is meaningless (it's just 0), so the low side shows
|
||||||
|
# the longest dry streak and the date it began instead.
|
||||||
|
days, dry_start = grading.longest_dry_streak(history)
|
||||||
|
low = f"{days}-day dry spell" if days else "—"
|
||||||
|
low_date = dry_start or "—"
|
||||||
|
else:
|
||||||
|
low, low_date = _fmt(key, r["min"]), r["min_date"]
|
||||||
rows.append({
|
rows.append({
|
||||||
"label": label,
|
"label": label,
|
||||||
"high": _fmt(key, r["max"]), "high_date": r["max_date"],
|
"high": _fmt(key, r["max"]), "high_date": r["max_date"],
|
||||||
"low": _fmt(key, r["min"]), "low_date": r["min_date"],
|
"low": low, "low_date": low_date,
|
||||||
})
|
})
|
||||||
breadcrumb = [("Home", f"{BASE}/"), ("Climate", f"{BASE}/climate"),
|
breadcrumb = [("Home", f"{BASE}/"), ("Climate", f"{BASE}/climate"),
|
||||||
(name, f"{BASE}/climate/{city['slug']}"), ("Records", None)]
|
(name, f"{BASE}/climate/{city['slug']}"), ("Records", None)]
|
||||||
|
|
|
||||||
24
grading.py
24
grading.py
|
|
@ -182,6 +182,30 @@ def all_time_records(df: pl.DataFrame) -> dict:
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def longest_dry_streak(df: pl.DataFrame) -> tuple[int, str | None]:
|
||||||
|
"""Longest run of consecutive days without measurable rain, and the ISO date the
|
||||||
|
streak began. A dry day is precip < RAIN_THRESHOLD; null precip counts as dry."""
|
||||||
|
if "precip" not in df.columns:
|
||||||
|
return (0, None)
|
||||||
|
d = df.select(["date", "precip"]).sort("date")
|
||||||
|
dates, precips = d["date"].to_list(), d["precip"].to_list()
|
||||||
|
best_len, best_start = 0, None
|
||||||
|
cur_len, cur_start = 0, None
|
||||||
|
for dt, p in zip(dates, precips):
|
||||||
|
wet = p is not None and not (isinstance(p, float) and np.isnan(p)) and p >= RAIN_THRESHOLD
|
||||||
|
if wet:
|
||||||
|
cur_len, cur_start = 0, None
|
||||||
|
else:
|
||||||
|
if cur_len == 0:
|
||||||
|
cur_start = dt
|
||||||
|
cur_len += 1
|
||||||
|
if cur_len > best_len:
|
||||||
|
best_len, best_start = cur_len, cur_start
|
||||||
|
start = best_start.isoformat() if best_start and hasattr(best_start, "isoformat") else (
|
||||||
|
str(best_start) if best_start else None)
|
||||||
|
return (best_len, start)
|
||||||
|
|
||||||
|
|
||||||
def _band_stats(samples: np.ndarray) -> dict | None:
|
def _band_stats(samples: np.ndarray) -> dict | None:
|
||||||
if samples.size == 0:
|
if samples.size == 0:
|
||||||
return None
|
return None
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<p class="records-note muted">Rainfall has no meaningful record low, so its “record low”
|
||||||
|
column shows the <b>longest run of consecutive days without measurable rain</b> and the
|
||||||
|
date that dry spell began.</p>
|
||||||
|
|
||||||
<p><a class="cta" href="{{ base }}/#{{ '%.5f,%.5f' | format(city.lat, city.lon) }}">Grade {{ name }}'s weather now →</a></p>
|
<p><a class="cta" href="{{ base }}/#{{ '%.5f,%.5f' | format(city.lat, city.lon) }}">Grade {{ name }}'s weather now →</a></p>
|
||||||
<p class="climate-foot muted"><a href="{{ base }}/climate/{{ city.slug }}">‹ Back to {{ name }} climate</a></p>
|
<p class="climate-foot muted"><a href="{{ base }}/climate/{{ city.slug }}">‹ Back to {{ name }} climate</a></p>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue