fix(climato): TX agrégé par MAX plutôt que moyenne inter-stations
All checks were successful
Deploy info-canicule / deploy (push) Successful in 1m30s

La moyenne des TX sur toutes les stations du département sous-estimait
systématiquement de 2-3°C à cause des stations en altitude. MAX est
la sémantique correcte pour un site canicule.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Florian 2026-05-27 22:09:11 +02:00
parent 003b49c297
commit 270242a685

View file

@ -37,7 +37,7 @@ function buildUrl(dept: string, period: string): string | null {
return `${BASE}/Q_${dept}_${period}_RR-T-Vent.csv.gz`;
}
type Agg = { tnSum: number; tnN: number; txSum: number; txN: number; tmSum: number; tmN: number; rrSum: number; rrN: number; stations: number };
type Agg = { tnSum: number; tnN: number; txMax: number; txN: number; tmSum: number; tmN: number; rrSum: number; rrN: number; stations: number };
function parseCsvInto(text: string, byDate: Map<string, Agg>): void {
const lines = text.split(/\r?\n/);
@ -60,19 +60,23 @@ function parseCsvInto(text: string, byDate: Map<string, Agg>): void {
const date = `${raw.slice(0, 4)}-${raw.slice(4, 6)}-${raw.slice(6, 8)}`;
let agg = byDate.get(date);
if (!agg) {
agg = { tnSum: 0, tnN: 0, txSum: 0, txN: 0, tmSum: 0, tmN: 0, rrSum: 0, rrN: 0, stations: 0 };
agg = { tnSum: 0, tnN: 0, txMax: -Infinity, txN: 0, tmSum: 0, tmN: 0, rrSum: 0, rrN: 0, stations: 0 };
byDate.set(date, agg);
}
agg.stations++;
const add = (raw: string | undefined, sum: 'tnSum' | 'txSum' | 'tmSum' | 'rrSum', n: 'tnN' | 'txN' | 'tmN' | 'rrN') => {
const addAvg = (raw: string | undefined, sum: 'tnSum' | 'tmSum' | 'rrSum', n: 'tnN' | 'tmN' | 'rrN') => {
if (!raw) return;
const v = parseFloat(raw.replace(',', '.'));
if (Number.isFinite(v)) { agg![sum] += v; agg![n]++; }
};
if (idx.tn !== -1) add(cols[idx.tn], 'tnSum', 'tnN');
if (idx.tx !== -1) add(cols[idx.tx], 'txSum', 'txN');
if (idx.tm !== -1) add(cols[idx.tm], 'tmSum', 'tmN');
if (idx.rr !== -1) add(cols[idx.rr], 'rrSum', 'rrN');
// TX: max across stations (not average) — hottest reading in the dept for canicule detection
if (idx.tx !== -1 && cols[idx.tx]) {
const v = parseFloat(cols[idx.tx].replace(',', '.'));
if (Number.isFinite(v)) { if (v > agg.txMax) agg.txMax = v; agg.txN++; }
}
if (idx.tn !== -1) addAvg(cols[idx.tn], 'tnSum', 'tnN');
if (idx.tm !== -1) addAvg(cols[idx.tm], 'tmSum', 'tmN');
if (idx.rr !== -1) addAvg(cols[idx.rr], 'rrSum', 'rrN');
}
}
@ -89,7 +93,7 @@ function aggregateDays(byDate: Map<string, Agg>): DayObservation[] {
.map(([date, agg]) => ({
date,
tn: agg.tnN > 0 ? +(agg.tnSum / agg.tnN).toFixed(1) : null,
tx: agg.txN > 0 ? +(agg.txSum / agg.txN).toFixed(1) : null,
tx: agg.txN > 0 ? +agg.txMax.toFixed(1) : null,
tm: agg.tmN > 0 ? +(agg.tmSum / agg.tmN).toFixed(1) : null,
rr: agg.rrN > 0 ? +(agg.rrSum / agg.rrN).toFixed(1) : null,
stations: agg.stations,