function anzahlTropennächte(data, threshold) {
const byYear = d3.group(data, d => d.Jahr);
return Array.from(byYear, ([Jahr, days]) => ({
Jahr,
Tropennächte: days.filter(d => d.tlmin >= threshold).length
}));
}
function maxTropennachtPeriode(data, threshold) {
const byYear = d3.group(data, d => d.Jahr);
return Array.from(byYear, ([Jahr, days]) => {
let maxRun = 0, currentRun = 0;
for (const d of days) {
if (d.tlmin >= threshold) { currentRun++; maxRun = Math.max(maxRun, currentRun); }
else { currentRun = 0; }
}
return { Jahr, Periode: maxRun };
});
}combined = {
const tropennächte = anzahlTropennächte(transpose(hw_data), schwelle);
const perioden = maxTropennachtPeriode(transpose(hw_data), schwelle);
const periodenMap = new Map(perioden.map(d => [d.Jahr, d.Periode]));
return tropennächte.map(d => ({
...d,
Periode: periodenMap.get(d.Jahr) ?? 0
}));
}Plot.plot({
style: { fontSize: "20px" },
marginLeft: 70,
marginTop: 40,
marginBottom: 50,
marks: [
Plot.barY(combined, { x: "Jahr", y: "Tropennächte", fill: "steelblue" }),
Plot.tip(combined, Plot.pointerX({ x: "Jahr", y: "Tropennächte",
title: d => `${d.Jahr}\nTropennächte: ${d.Tropennächte}\nLängste Periode: ${d.Periode} Nächte`
}))
],
x: { tickFormat: "d", label: "Jahr", ticks: [...d3.range(1950, 2026, 10), 2026] },
y: { label: "Anzahl Tropennächte", tickFormat: d => Number.isInteger(d) ? d : "" }
})Plot.plot({
style: { fontSize: "20px" },
marginLeft: 70,
marginTop: 40,
marginBottom: 50,
marks: [
Plot.barY(combined, { x: "Jahr", y: "Periode", fill: "steelblue" }),
Plot.tip(combined, Plot.pointerX({ x: "Jahr", y: "Periode",
title: d => `${d.Jahr}\nTropennächte: ${d.Tropennächte}\nLängste Periode: ${d.Periode} Nächte`
}))
],
x: { tickFormat: "d", label: "Jahr", ticks: [...d3.range(1950, 2026, 10), 2026] },
y: { label: "Längste Tropennacht-Periode (Nächte)", tickFormat: d => Number.isInteger(d) ? d : "" }
})