Skip to content

feat(mit-incidentalita): plateau 2013, indice di mortalità e stagionalità - #264

Open
Lore222 wants to merge 1 commit into
dataciviclab:mainfrom
Lore222:feat/mit-incidentalita-arricchita
Open

Lore222 wants to merge 1 commit into
dataciviclab:mainfrom
Lore222:feat/mit-incidentalita-arricchita

Conversation

@Lore222

@Lore222 Lore222 commented Sep 22, 2026

Copy link
Copy Markdown

Sintesi

Arricchisce la pagina mit-incidentalita con tre letture che oggi mancano del tutto: il plateau della mortalità dal 2013, il calo dell'indice di mortalità (morti ogni 100 incidenti) e la stagionalità mensile (agosto come mese più letale). Tutti i numeri restano calcolati a build-time dal parquet: nessuna cifra scritta a mano, KPI e grafici si aggiornano da soli.

I contenuti derivano dall'analisi dataciviclab/dataciviclab#451 (README + notebook + figure) e vengono qui resi data-driven nella forma richiesta dallo standard delle pagine dataset.

Contesto collegato

Nessuna issue dedicata: nasce dalla richiesta di arricchire la pagina esistente dopo l'analisi #451. Nessun loader modificato, nessun dataset nuovo.

Cosa cambia

  • Miglioramento pagina dataset esistente (src/dataset/mit-incidentalita.md)
  • Nuovo dataset — pagina explorer
  • Bug fix frontend (data loader / layout / performance)
  • Aggiornamento config / catalogo
  • Modifica struttura dati upstream
  • Documentazione

Dettaglio dei blocchi

Sezione Prima Ora
Intro solo "-X% morti dal 2001" plateau (vite/anno prima vs dopo il 2013), calo dell'indice di mortalità, letalità extra di agosto
KPI cards 3 4 (aggiunta "Morti ogni 100 incidenti")
1. Riepilogo annuale incidenti/morti/feriti + incidenti mortali (grafico e testo)
2. Trend linea dei soli incidenti serie indicizzata base 2001=100 su incidenti/morti/feriti
3. La discesa si ferma — nuovo: variazioni annue dei morti, colore diverso dal 2013; 309 vite/anno → 10
4. Indice di mortalità — nuovo: trend della letalità (2,90 → 1,93) + avviso sul salto 2012→2013
5. Stagionalità — nuovo: morti medi per mese + letalità per mese, agosto evidenziato
Tabelle dettaglio mensile dettaglio mensile arricchito (incidenti mortali, decimals: 2) + nuova serie annuale completa
Limiti 3 bullet generici copertura (216 mesi), granularità nazionale, discontinuità di rilevazione 2013, indici calcolati sul rapporto aggregato

Standard check

  • Niente toLocaleString — solo num(), numFix(), tableFormat() da format-utils.js
  • tableFormat e Inputs.table in celle separate
  • Mappe: non applicabile (dato nazionale)
  • Niente duckdb.connect() — il loader non è stato toccato
  • Sidebar: non toccata (observablehq.config.js invariato)
  • data_driven: true rispettato: nessuna cifra hardcoded nella prosa
  • Sezione Limiti aggiornata
  • Colori Plot literal, non field name

Verifica

node scripts/lint-standards.mjs   # ✅ 47 pagine, 0 errori
git diff --stat                   # 1 file cambiato, +259 −43

Nota sull'ambiente: npm run lint completo e npm run build non sono stati eseguiti in locale perché la macchina di sviluppo ha Node 19 e Python 3.9, mentre il repo richiede Node 20 e Python 3.12+ con lab-connectors (i loader usano sintassi 3.10+). Come validazione alternativa ho ricostruito l'esatto output del data loader leggendo il parquet clean da GCS (216 righe) ed eseguito le 22 celle JS della pagina in Node con il vero format-utils.js:

  • 22 celle, 0 errori di sintassi, tutte le interpolazioni ${...} della prosa risolvono;
  • 0 pattern di numeri hardcoded rilevati sul testo;
  • valori coerenti con l'analisi #451: morti −53%, indice di mortalità −33% (2,90 → 1,93), plateau −51 vittime dal 2013, 309 → 10 vite/anno, agosto 3,03 vs febbraio 2,06 (+47%), agosto 2º mese su 12 per numero di incidenti;
  • il blocco 1 regge al cambio anno del selettore (verificato su 2001: 6.455 incidenti mortali, indice 2,90; e 2012: 1,99).

Checklist PR

  • Perimetro stretto: una PR = un dataset
  • Motivazione della PR (nessuna issue collegata: arricchimento di pagina esistente su richiesta, contenuti dall'analisi #451)

Note per chi revisiona

  • const SOGLIA = 2013 è una costante editoriale (punto di svolta della serie), nello stesso spirito della soglia 2020 in entrate-stato.md. Se cambia il parquet, va rivista a mano: non è derivata dal dato.
  • Gli indici della pagina sono calcolati sul rapporto aggregato (morti/incidenti del periodo), non come media dei valori mensili pubblicati dalla fonte: è dichiarato nei Limiti e nella nota del dettaglio mensile.
  • La nota "Come leggerlo" sul 2012→2013 serve a evitare la lettura sbagliata: il salto dell'indice di mortalità è un effetto di composizione legato alla discontinuità nella rilevazione degli incidenti, non un peggioramento improvviso delle strade.
  • Il data loader src/data/mit-incidentalita.json.py non è stato modificato: carica già incidenti_mortali, indice_gravita e indice_lesivita, sufficienti per i nuovi blocchi.

@Lore222 Lore222 changed the title feat(mit-incidentalita): plateau 2013, indice di mortalita e stagionalita feat(mit-incidentalita): plateau 2013, indice di mortalità e stagionalità Sep 22, 2026
@Gabrymi93

Copy link
Copy Markdown
Member

Fix trovati in review — 2 fix da applicare

Ciao Lore, ho tirato il branch locale e revisionato. La PR è solida, narrative forte, dati tutti data-driven. Due fix tecnici:

1. domain: [0, null] rompe il rendering dei grafici

Righe 275 e 323 (sezioni 4 e 5): domain: [0, null] non è un valore valido per Observable Plot. L'unico file nel codebase che usa null come endpoint del dominio — tutti gli altri usano bound numerici espliciti ([0, 100], [0, 40], ecc.).

Fix: rimuovere domain: [0, null] e lasciare che Plot auto-scali l'asse Y.

-  y: {grid: true, label: "morti ogni 100 incidenti", domain: [0, null]},
+  y: {grid: true, label: "morti ogni 100 incidenti"},

2. Mesi ordinati alfabeticamente, non cronologicamente

I due grafici stagionali (bar chart morti medi + linea letalità) usano x: {label: null} — Plot ordina le stringhe alfabeticamente, risultato: Agosto, Aprile, Dicembre, Febbraio… La linea della letalità connette i punti in ordine sbagliato.

Fix: forzare il dominio cronologico con domain: stagionale.map(d => d.mese) (l'array è già ordinato per mese_numero).

-  x: {label: null},
+  x: {label: null, domain: stagionale.map(d => d.mese)},

Entrambi i fix applicati nel branch pr-264 — possono essere cherry-pickati o applicati a mano.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants