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)

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
Runtimes (1)