Analisi Covid-19 Italia
{:deps {org.clojure/clojure {:mvn/version "1.10.1"}
org.clojure/data.csv {:mvn/version "1.0.0"}
cheshire/cheshire {:mvn/version "5.10.0"}
metosin/jsonista {:mvn/version "0.2.7"}}}
Extensible Data Notation
curl https://raw.githubusercontent.com/pcm-dpc/COVID-19/master/dati-json/dpc-covid19-ita-andamento-nazionale.json > data.json
curl https://raw.githubusercontent.com/pcm-dpc/COVID-19/master/dati-json/dpc-covid19-ita-regioni.json > data_region.json
curl https://raw.githubusercontent.com/pcm-dpc/COVID-19/master/dati-json/dpc-covid19-ita-province.json > data_province.json
Retrieve data
3.4s
date
0.9s
italy-population.csv
2.18 KBDownload(require [cheshire.core :as json])
(def national-data (json/parse-string (slurp "/data.json") true))
(reverse national-data)
_(keys (first national-data))
3.3s
(def selected-keys [:totale_casi :dimessi_guariti :deceduti :tamponi :tamponi_test_molecolare :totale_ospedalizzati :terapia_intensiva :ingressi_terapia_intensiva :data])
(def clean-data (distinct (map (select-keys % selected-keys) national-data)))
(def a (take-last 5 clean-data))
(defn calculate-delta [coll]
(map (fn [a b]
(into {} (map (fn [[k1 v1] [_ v2]]
(case k1
:data [k1 v1]
[k1 (when (and v2 v1)
(- v2 v1))]))
a b)))
coll (rest coll)))
(defn moving-average [n coll]
(let [[n1 n2] (split-with nil? coll)]
(concat n1 (when-let [[x & xs] (seq n2)]
(map (/ % n)
(reductions + (* n x)
(map - xs (concat (repeat n x) xs))))))))
(def incremental-data (calculate-delta clean-data))
(defn plot [input plot-spec opts]
(let [incremental-data (calculate-delta input)]
{:nextjournal/viewer :plotly}
{:data (map (fn [{:keys [key color incremental? legend]}]
{:name legend
:mode "lines"
:line {:color color}
:x (map (comp (apply str %) (take 10 %) :data) input)
:y (cond->> (map key (if incremental? incremental-data input)) (:average opts) (moving-average (:average opts)))}) plot-spec)
:layout {:margin {:l 80 :b 50 :r 50 :t 50}
:xaxis {:autotick true
:automargin true
:showticklabels true}
:yaxis {:automargin true}
}}))
(def c (last clean-data))
(def d (last incremental-data))
(clojure.pprint/pprint
{:nuovi-casi (:totale_casi d)
:tamponi (:tamponi d)
:ultimo-dato (:data c)
:tamponi-pcr (:tamponi_test_molecolare d)
:dimessi-guariti (:dimessi_guariti d)
:nuovi-deceduti (:deceduti d)
:delta-terapia-intensiva (:terapia_intensiva d)
:nuovi-ingressi-terapia-intensiva (:ingressi_terapia_intensiva c)})
0.8s
(require [clojure.data.csv :as csv]
[clojure.set :as set])
(def pop (->> (csv/read-csv (slurp italy-population.csv))
(drop 1)
(map (fn [[k n]] [k (Integer/parseInt n)]))
(into {})
))
(def keys-to-rename {"Valle d'Aosta / Vallée d'Aoste" "Valle d'Aosta"
"Bolzano / Bozen" "P.A. Bolzano"
"Trento" "P.A. Trento"})
(def pop-100k
(into {} (map (fn [[k v]] [k (float (/ v 100000))]) (set/rename-keys pop keys-to-rename))))
(sort-by second > pop-100k)
0.6s
Nuovi positivi
Dati grezzi
(def positive-plot
[{:key :totale_casi
:color "orchid"
:legend "Nuovi positivi"
:incremental? true}
{:key :deceduti
:color "tomato"
:legend "Deceduti"
:incremental? true}
{:key :dimessi_guariti
:color "limegreen"
:legend "Guariti"
:incremental? true}])
(plot clean-data positive-plot {})
_(map (comp (apply str %) (take 10 %) :data) clean-data)
0.7s
Media mobile di 7-giorni
(plot clean-data positive-plot {:average 7})
0.7s
Test e nuovi positivi
Dati grezzi
(def tests-plot
[{:key :totale_casi
:color "orchid"
:legend "Nuovi positivi"
:incremental? true}
{:key (fn [r] (or (:tamponi_test_molecolare r)
(:tamponi r)))
:color "darkcyan"
:legend "Tamponi"
:incremental? true}])
(plot clean-data tests-plot {})
0.5s
Media mobile di 7 giorni
(plot clean-data tests-plot {:average 7})
0.5s
Ricoveri e TI (dato attuale)
(def hospital-plot
[{:key :totale_ospedalizzati
:color "red"
:legend "Ricoverati"
:incremental? false}
{:key :terapia_intensiva
:color "orange"
:legend "Terapia Intensiva"
:incremental? false}])
(plot clean-data hospital-plot {})
0.6s
Ingressi giornalieri TI
(def ti-plot
[{:key :ingressi_terapia_intensiva
:color "red"
:legend "Ingressi TI"
:incremental? false}])
(plot clean-data ti-plot {:average 7 :last 60})
0.8s
Dati regionali (normalizzati, per 100k abitanti)
(def regional-data (json/parse-string (slurp "/data_region.json") true))
regional-data
8.3s
(defn region-data [region-name]
(->>
regional-data
(filter (= (:denominazione_regione %) region-name))
(map (select-keys % selected-keys))
distinct))
(def regions
{"Lombardia" "black"
"Emilia-Romagna" "darkgreen"
"Veneto" "deepskyblue"
"Sicilia" "gold"
"Piemonte" "brown"
"Marche" "orange"
"Toscana" "chocolate"
"Lazio" "red"
"Liguria" "grey"
"Campania" "skyblue"
"Puglia" "orchid"})
(def data-by-region
(->>
(keys regions)
(map (fn [r] [r (region-data r)]))
(into {})))
(defn y [region-name data {:keys [measure incremental? by-100k? average last]}]
(let [values (map measure (if incremental? (calculate-delta data) data))
result (cond->> values
by-100k? (map (fn [x] (when x (/ x (get pop-100k region-name)))))
average (moving-average average)
last (take-last last))]
result))
(defn plot-regional-data [{:keys [last] :as opts}]
{:nextjournal/viewer "plotly"}
{:data (mapv (fn [[region-name color]]
(let [data (get data-by-region region-name)]
{:name region-name
:mode "lines"
:line {:color color}
:x (cond->> (map (comp (apply str %) (take 10 %) :data) data)
last (take-last last))
:y (y region-name data opts)}))
regions)
:layout {:xaxis {:autotick true
:automargin true}}}
)
0.1s
Nuovi casi
(plot-regional-data {:measure :totale_casi
:by-100k? true
:incremental? true
:average 7
:last 90})
1.1s
Tamponi
(plot-regional-data {:measure (fn [r] (or (:tamponi_test_molecolare r)
(:tamponi r)))
:by-100k? true
:incremental? true
:average 7
:last 90})
0.7s
Ospedalizzati (attuale)
(plot-regional-data {:measure :totale_ospedalizzati
:by-100k? true
:incremental? false
:average 1
:last 60})
0.6s
TI (attuale)
(plot-regional-data {:measure :terapia_intensiva
:by-100k? true
:incremental? false
:average 1
:last 60})
0.5s
Ingressi TI
(plot-regional-data {:measure :ingressi_terapia_intensiva
:by-100k? true
:incremental? false
:average 7
:last 60})
0.5s
Dati provinciali
(def provincial-data (json/parse-string (slurp "/data_province.json") true))
(defn province-data [province-name]
(->>
provincial-data
(filter (= (:denominazione_provincia %) province-name))
(map (select-keys % selected-keys))
distinct))
(def provinces
{"Milano" "black"
"Ravenna" "darkgreen"
"Forlì-Cesena" "red"
"Ferrara" "gold"
"Sondrio" "brown"
"Rimini" "skyblue"})
(def data-by-province
(->>
(keys provinces)
(map (fn [r] [r (province-data r)]))
(into {})))
(defn yy [region-name data {:keys [measure incremental? by-100k? average last]}]
(let [values (map measure (if incremental? (calculate-delta data) data))
result (cond->> values
by-100k? (map (fn [x] (when x (/ x (get pop-100k region-name)))))
average (moving-average average)
last (take-last last))]
result))
(defn plot-provincial-data [{:keys [last] :as opts}]
{:nextjournal/viewer "plotly"}
{:data (mapv (fn [[province-name color]]
(let [data (get data-by-province province-name)]
{:name province-name
:mode "lines"
:line {:color color}
:x (cond->> (map (comp (apply str %) (take 10 %) :data) data)
last (take-last last))
:y (yy province-name data opts)}))
provinces)
:layout {:xaxis {:autotick true
:automargin true}}})
0.7s
(plot-provincial-data {:measure :totale_casi
:incremental? true
:by-100k? true
:average 7
:last 60})
2.3s