diff --git a/content.py b/content.py index 09fcf9e..16f2347 100644 --- a/content.py +++ b/content.py @@ -226,10 +226,22 @@ def _monthly_normals(history) -> list[dict]: return rows +def _extreme(metric_rec, key: str) -> dict | None: + """One extreme of a metric — key 'max' (warmest) or 'min' (coldest) — as the + two-unit value, its heat-map tier, and the date it occurred.""" + if not metric_rec: + return None + v = metric_rec[key] + return {"txt": _temp(v), "f": v, "cls": temp_class(v), "date": metric_rec[f"{key}_date"]} + + def _period_records(history, months: list[int]) -> dict: - """Record high (tmax) and record low (tmin), with the dates they occurred, over a - set of calendar months — the shared primitive behind the monthly and seasonal - records tables. Reuses grading.all_time_records on the month-filtered archive.""" + """For a set of calendar months, the record *warmest and coldest* of BOTH the + daytime high (tmax) and the overnight low (tmin) — four extremes with dates. + + So each metric shows both ends: the daytime high's hottest day and the coldest a + day ever stayed (its record-low high), and the overnight low's mildest night and + its record low. Reuses grading.all_time_records on the month-filtered archive.""" if len(months) == 1: sub = history.filter(pl.col("date").dt.month() == months[0]) else: @@ -237,12 +249,8 @@ def _period_records(history, months: list[int]) -> dict: rec = grading.all_time_records(sub) if not sub.is_empty() else {} tmax, tmin = rec.get("tmax"), rec.get("tmin") return { - "high": _temp(tmax["max"]) if tmax else "—", - "high_f": tmax["max"] if tmax else None, - "high_date": tmax["max_date"] if tmax else "—", - "low": _temp(tmin["min"]) if tmin else "—", - "low_f": tmin["min"] if tmin else None, - "low_date": tmin["min_date"] if tmin else "—", + "high": {"warm": _extreme(tmax, "max"), "cold": _extreme(tmax, "min")}, + "low": {"warm": _extreme(tmin, "max"), "cold": _extreme(tmin, "min")}, } diff --git a/templates/records.html.j2 b/templates/records.html.j2 index cd6985d..61ce920 100644 --- a/templates/records.html.j2 +++ b/templates/records.html.j2 @@ -4,6 +4,15 @@ {% block canonical_path %}{{ canonical_path }}{% endblock %} {% block jsonld %}{% endblock %} {% block content %} +{# A metric's two extremes — ▲ warmest and ▼ coldest it has ever been — as tinted + chips with the date each occurred. Used for the daytime-high and overnight-low + columns of the month and season tables. #} +{% macro extremes(metric) %} +{% if metric and metric.warm and metric.cold %} +
{{ metric.warm.txt }}{{ metric.warm.date }}
+
{{ metric.cold.txt }}{{ metric.cold.date }}
+{% else %}—{% endif %} +{% endmacro %} @@ -20,17 +29,18 @@

Records by month

-

The warmest and coldest {{ name }} has ever been in each calendar month. Tap a month for its full - averages and typical range.

+

The warmest (▲) and coldest (▼) both the daytime high and the overnight low have ever been in + each calendar month — so each column shows its record high and its record low. Tap a + month for its full averages and typical range.

- - +
MonthRecord highRecord low
+ {% for m in monthly %} - - + + {% endfor %} @@ -40,17 +50,17 @@

Records by season

-

Meteorological seasons for the {{ hemisphere }} Hemisphere — each a three-month span — and the - most extreme {{ name }} has recorded within each.

+

The warmest (▲) and coldest (▼) both the daytime high and the overnight low have reached in each + meteorological season ({{ hemisphere }} Hemisphere — each a three-month span).

-
MonthDaytime highOvernight low
{{ m.name }}{{ m.high }}{{ m.high_date }}{{ m.low }}{{ m.low_date }}{{ extremes(m.high) }}{{ extremes(m.low) }}
- +
SeasonRecord highRecord low
+ {% for s in seasonal %} - - + + {% endfor %} diff --git a/tests/test_content.py b/tests/test_content.py index b8954b0..130ccc2 100644 --- a/tests/test_content.py +++ b/tests/test_content.py @@ -134,11 +134,21 @@ def test_climate_pages_are_colour_coded(client): assert "t-cell t-" in city # tinted temperature cells in the normals table assert "range-fill" in city and "--c1:var(--" in city # the monthly range strip's gradient bars recs = client.get(f"{B}/climate/{SLUG}/records").text - assert "t-cell t-" in recs + assert "t-inline t-" in recs # tinted record chips month = client.get(f"{B}/climate/{SLUG}/july").text assert "t-inline t-" in month # tinted hero numbers + records +def test_records_show_both_extremes_per_metric(client): + # Each metric column shows BOTH its record warmest (▲) and coldest (▼) — so the + # daytime high carries its record-low high, and the overnight low its record-high low. + b = client.get(f"{B}/climate/{SLUG}/records").text + assert "Daytime high" in b and "Overnight low" in b + assert "▲" in b and "▼" in b + # 12 months × 2 metric columns × 2 extremes = 48 chips just in the monthly table. + assert b.count('class="rec-ext"') >= 48 + + def test_hub_glossary_about(client): assert client.get(f"{B}/climate").status_code == 200 assert client.get(f"{B}/glossary").status_code == 200
SeasonDaytime highOvernight low
{{ s.name }} ({{ s.span }}){{ s.high }}{{ s.high_date }}{{ s.low }}{{ s.low_date }}{{ extremes(s.high) }}{{ extremes(s.low) }}