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"}}}
deps.edn
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
3.4s
Retrieve dataBash in Clojure
italy-population.csv
2.18 KB
(require '[cheshire.core :as json])
(def national-data (json/parse-string (slurp "/data.json") true))
(reverse national-data)
#_(keys (first national-data))
3.5s
Clojure

(def selected-keys [:totale_casi :dimessi_guariti :deceduti :tamponi :tamponi_test_molecolare :totale_ospedalizzati :terapia_intensiva :ingressi_terapia_intensiva :data])
(def clean-data (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)
   :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
Clojure
(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.9s
Clojure
(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.6s
Clojure

7-day average

(plot clean-data positive-plot {:average 7})
0.7s
Clojure
(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.4s
Clojure

7-day average tests vs new cases

(plot clean-data tests-plot {:average 7})
0.5s
Clojure

Dati regionali

(def regional-data (json/parse-string (slurp "/data_region.json") true))
regional-data
8.3s
Clojure
(defn region-data [region-name]
  (->>
    regional-data
    (filter #(= (:denominazione_regione %) region-name))
    (map #(select-keys % selected-keys))))
(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.2s
Clojure

Nuovi casi

(plot-regional-data {:measure :totale_casi
                     :incremental? true
                     :average 7
                     :last 90})
1.1s
Clojure

Tamponi

(plot-regional-data {:measure (fn [r] (or (:tamponi_test_molecolare r)
                                        (:tamponi r)))
                     :incremental? true
                     :average 7
                     :last 90})
0.7s
Clojure

Ingressi TI

(plot-regional-data {:measure :ingressi_terapia_intensiva
                     :by-100k? false
                     :incremental? false
                     :average 7
                     :last 30})
0.5s
Clojure

Regionale per 100.000 abitanti

Nuovi casi

(plot-regional-data {:measure :totale_casi
                     :by-100k? true
                     :incremental? true
                     :average 7
                     :last 90})
0.6s
Clojure

Tamponi

(plot-regional-data {:measure (fn [r] (or (:tamponi_test_molecolare r)
                                        (:tamponi r)))
                     :by-100k? true
                     :incremental? true
                     :average 7
                     :last 90})
0.8s
Clojure
(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))))
(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.5s
Clojure
(plot-provincial-data {:measure :totale_casi
                       :incremental? true
                       :by-100k? true
                       :average 7
                       :last 90})
1.5s
Clojure
Runtimes (1)