COVID-19 în Romania – un graf

15 min read

Această postare este despre vizualizările pe care le-am făcut despre COVID-19 în România, şi despre data visualization în general.
Dacă te grabeşti, poţi merge direct la grafice.

Ei bine, 2020 a fost o adevărată provocare, şi a schimbat viaţa multor oameni. A fost învăluit în frică, furie, suferinţă, pierdere, a scos la iveală ce-i mai rău din mulţi dintre noi. Dar de asemenea ne-a ajutat să ne ne punem întrebări despre existenţa noastră, stilul nostru de viaţă, a scos la suprafaţă empatie si a apropiat oamenii (din unele puncte de vedere).

Primul caz de COVID-19 a apărut în România pe 26 februarie, 2020, există 697898 cazuri confirmate până la momentul scrierii, şi 17369 decese (19 februarie 2021). Pe 27 decembrie 2020, a început vaccinarea şi în România, odată cu sosirea primelor tranşe de vaccin Pfizer-BioNTech şi Moderna în ţara noastră.

Astfel, chiar dacă SARSCoV-2 se află printre noi, îmi place să cred că încă există speranţă. Şi că, de asemenea, am învăţat ceva din greşelile noastre, după un an de carantine, incertitudini şi unele greşeli regretabile din partea oficialilor noştri, care într-un final a segregat oamenii şi a accentuat prăpastia socială.

Am tot amânat să scriu o postare pe blog, pentru că este un subiect trist, şi implică oameni adevăraţi. Dar când am făcut aceste grafice, m-am gândit că suntem cu toţii în asta, şi poate observarea unei aglomerări de cazuri în oraşul meu ne va ajuta pe mine, precum şi pe alţii, să evităm contaminarea, sau să prevenim răspândirea. Am simţit nevoia să vizualizez modul de răspândire a virusului, pentru a înţelege mai bine fenomenul, şi de asemenea pentru a-mi ţine mintea ocupată.

În februarie, oamenii faini din echipa geo-spațial.org s-au hotărât să înceapă să monitorizeze evoluţia cazurilor şi legăturie dintre ele. Împreună cu voluntarii, au început să adune date din rapoartele oficiale guvernamentale, în fiecare zi, şi le-au completat cu informaţii din media şi din alte surse. De asemenea, au creat Coronavirus COVID-19 România, o aplicaţie care expunea statisticile prin intermediul a diverse hărţi, grafice sau diagrame. Datele colectate au fost puse la dispoziţie gratuit, în format JSON printr-un API dedicat.

Faptul că Coronavirus COVID-19 România s-a străduit să furnizeze date corecte şi complete, în pofida raportărilor incomplete şi întârziate de la guvern, m-a făcut să sper că oficialii ar folosi datele întreţinute şi graficele pentru a organiza mai bine resursele şi a preveni răspândirea. Din punctul meu de vedere, într-un final niciunui oficial nu i-a păsat de date, de modele spaţiale, sau de previziunile pe care le-au făcut statisticienii.. Dar măcar a adus un pic mai multă transparenţă asupra datelor.

M-am oferit să ajut echipa geo-spatial.org pe partea de vizualizare de date, am făcut un grafic interactiv al evoluţiei cazurilor pe zi şi l-am publicat pe website. La început, codul a fost integrat direct în aplicaţie, dar după o vreme am decis să îl public pe GitHub şi să îl expun prin intermediul gh-pages.

De asemenea, am făcut grafice interactive pe tema relaţionărilor dintre cazuri, o hartă care arată cum sunt grupate cazurile în interiorul fiecărui judeţ, o cronologie care arate cum sunt cazurile legate de-a lungul timpului, şi o diagramă treemap a distribuţiei cazurilor pe judeţ.

COVID-19 în România – Cazuri pe zile

Sursa de date: https://covid19.geo-spatial.org/api/dashboard/getDailyCaseReport
Codul: https://github.com/alexaac/covid-19-ro-cases-per-day
Live: https://maptheclouds.com/covid-19-ro/cases-per-day/ / https://covid19.geo-spatial.org/
Tip: line graph

De ce am făcut acest grafic?

Am vrut să monitorizez schimbarea numărului de cazuri de-a lungul timpului. Graficul este de la sine înţeles, arată evoluţia numărului de cazuri pe zile.

Graficele liniare sunt folosite pentru a afişa valori cantitative de-a lungul unui interval continuu sau a unei perioade de timp. Un grafic liniar se foloseşte cel mai frecvent pentru a arăta tendinţe şi a analiza cum s-au schimbat datele de-a lungul timpului. (src)

Am folosit grafice cumulative, nu scări logaritmice, dar i-am permis utilizatorului să selecteze grafice detaliate pentru intervale mai mici de timp.

Pe graficele cumulative, punctul care reprezintă datele pentru fiecare zi este totalul sumelor tuturor cazurilor confirmate de până acum. Acestea reprezintă o unealtă excelentă pentru vizualizarea extinderii maxime a epidemiei de până în prezent. Dar pericolul este că fac lucrurile să arate mai rău decât sunt, pentru că numărul total de cazuri confirmate încă de la începutul epidemiei poate doar să crească, nu şi să scadă. Această metodă îngreunează observarea momentului în care ratele de creştere încetinesc, pentru că trebuie să te uiţi după un platou pe curbă, mai degrabă decât după o coborâre. (src)

Pe o scară logaritmică, axul vertical al grafului (axa y) este gradată prin ordine de magnitudine (1, 10, 100, 1,000) mai degrabă decât prin incremente egale (10, 20, 30, 40). Acest fapt practic „comprimă” axa y astfel încât numerele mari să nu distorsioneze întregul grafic. Dacă o epidemie creşte exponenţial, cu siguranţă are mai mult sens să-l trasăm în modul acesta deoarece linia de tendinţă poate să „ţină pasul” cu numerele în loc să urce drept în sus. Un dezavantaj ar fi că acesta este clar un mod mai abstract de a inspecta datele, aşa că trebuie să cunoşti cum funcţionează o scară logaritmică înainte de a o înţelege în mod semnificativ. (src)

Detalii de implementare

Am făcut trei grafice cumulative, pentru cazurile confirmate, recuperări şi pierdute, şi utilizatorul poate vedea mai multe informaţii la trecerea mouse-ului peste puncte (hover). Mai târziu, am adăugat un grafic pentru cazurile active, şi o funcţionalitate numită brush, care permite utilizatorului să selecteze porţiuni din cronologie pe o suprafaţă situată dedesubtul graficelor principale, astfel încât graficul să expună date doar pentru intervalul de timp selectat.

Ultimele elemente pe care le-am adăugat au fost încă trei grafice pentru cazuri noi pe zi, şi un meniu vertical (dropdown), ascuns iniţial, care permite utilizatorului să aleagă dintre grafice.

Ce ar mai fi de făcut

  • Teste unitare
  • Crearea unei scări logaritmice alternative

COVID-19 în România – Relațiile dintre cazuri

Vezi câţi oameni au fost infectaţi de fiecare persoană. În graficul de mai jos, fiecare cerc reprezintă o persoană, mărimea lui este proporţională cu câţi oameni a infectat (= s-au aflat în zona unde virusul a fost răspândit de persoana infectată) iar culoarea reprezintă fie starea (confirmat, eliberat din spital, decedat), judeţul, genul sau vârsta.

Vezi cum sunt legaţi unul de celălalt oamenii infectaţi. Când o persoană s-a infectat şi a fost cunoscută sursa, acest lucru a fost considerat drept conexiune, şi reprezentat drept o linie curbă.

Vezi unde ar putea apărea focare. Grupările de oameni, create pe baza conexiunilor, ar putea scoate la iveală posibile focare şi ne-ar putea ajuta să descoperim locurile şi circumstanţele care pot conduce la focare.

Explorează. Treci pe deasupra fiecărei persoane pentru a vedea cu câţi oameni a intrat în contact, mai multe detalii, şi link-ul web către articolul original din media. Selectează altă temă pentru a colora toţi oamenii în funcţie de judeţ, gen, localizare sau stare. Zoom înăuntru pentru a afişa etichele, şi pan pentru a naviga. Schimbă limba (română sau engleză) după preferinţe.

Sursa de date: https://covid19.geo-spatial.org/api/statistics/getCaseRelations
Codul: https://github.com/alexaac/covid-19-ro-cases-relations
Live: https://maptheclouds.com/covid-19-ro/cases-relations/en/ / https://covid19.geo-spatial.org/statistici/relationare-cazuri?chart=covid-19-ro-cases-relations
Tip: network diagram
Proiectul iniţial: https://github.com/alexaac/covid-19-ro-cases-relations-all
Ultima actualizare a datelor: 30 iulie 2020.

De ce am făcut acest grafic?

Am vrut să văd cum erau legate cazurile confirmate, cum s-a răspândit virusul de la primele cazuri provenite din alte ţări, până la transmiterea în interiorul comunităţii. Acest gen de vizualizare ar evidenţia aglomerările de cazuri care ar putea duce la apariţia de focare, şi ar necesita mai multă atenţie din partea oficialilor.

În martie, am văzut un articol pe Kontinentalist despre cum erau legate cazurile în Singapore, aşa că m-am oferit că creez un grafic similar, pentru România. Am făcut un nou repository Github, am creat un grafic iniţial, am înregistrat codul free şi l-am expus prin gh-pages.

Cea mai bună cale de a arăta legăturile dintre oameni a fost o diagramă de reţea, sau o force layout în lumea D3.js.

Algoritmii de desenare a grafului direcţionat de forţe (Force-directed graph) sunt o categorie de algoritmi de desenare a grafurilor într-un mod plăcut din punct de vedere estetic. Scopul lor este de a poziţiona nodurile grafului în spaţiul bidimensional sau tridimensional astfel încât toate muchiile să fie cât mai aproape de aceeaşi lungime, şi să se intersecteze cât mai puţine muchii posibil, prin distribuirea de forţe între seturile de muchii şi seturile de noduri pe baza poziţiilor lor relative, şi apoi prin folosirea acestor forţe fie pentru a simula mişcarea muchiilor şi nodurilor, fie pentru a le diminua energia. (src)

O diagramă de reţea (Network Diagram), cunoscută şi sub numele de graf de reţea (Network Graph), hartă a reţelei (Network Map), diagramă nod-legătură (Node-Link Diagram) […] arată cum sunt lucrurile interconectate prin folosirea de noduri / vertex-uri (vertices) şi linii de legătură pentru a reprezenta conexiunile dintre ele şi a aduce lumină asupra tipului de relaţii dintre un grup de entităţi. De obicei, nodurile sunt desenate ca mici puncte sau cercuri, dar se pot folosi şi simboluri. Legăturile sunt afişate de obicei ca linii simple conectate între noduri. Totuşi, în unele diagrame de reţea, nu toate nodurile şi link-urile sunt create egale: pot fi vizualizate variabile adiţionale, de exemplu, prin facerea mărimii nodului sau grosimii link-ului proporţionale cu o valoare atribuită. (src)

Detalii de implementare

Am pregătit simularea de forţe D3.js astfel ca nodurile să fie afişate în jurul unui centru de gravitaţie, cazurile să fie desenate ca puncte, legăturile dintre ele ca linii, iar forţele de atracţie-respingere să distribuie automat toate elementele în spaţiul de desenat (sau cadru).

A trebuit să găsesc o soluţie pentru a adăuga ţările sursă la simulare, şi la un moment dat am decis să renunţăm la nodurile care nu erau legate de alte cazuri din comunitate.

Apoi, am integrat codul într-o platformă de lucru pentru limbajul JavaScript (framework), svelte, şi am adăugat diverse funcţionalităţi aplicaţiei, despre care am crezut că ar fi utile: afişare pe hartă, gruparea cazurilor pe judeţe, afişarea cazurilor pe un grafic cronologic, ordonate după zi şi stivuite. Aşezare în pagină în funcţie de rezoluţia ecranului, legende, navigare – mărire şi deplasare, un buton play care ar trece prin fiecare caz, informaţii despre caz într-un pop-up, link web către articolul sursă, afişarea etichetelor în funcţie de zoom. Colorare după judeţ, gen, vârstă, stare.

Provocări

Odată cu creşterea numărului de cazuri, a trebuit să mă gândesc la probleme de performanţă. Am realizat că D3.js nu a gândit ‘force layout-ul’ să fie folosit pentru mii şi mii de noduri, pentru că ar fi încărcat prea tare DOM-ul (Document Object Model). De asemenea mi-am dat seama că nu este indicat să afişezi atâta informaţie deodată, şi că ar fi mai bine să o agreghezi la un zoom mai mic.

Totuşi, încă am vrut să văd tiparul general şi să afişez toate nodurile, aşa că am încercat să măresc performanţa prin înlăturarea wrapper-ului svelte, şi să separ aplicaţia în funcţie de tipul diagramei.

De asemenea am încercat să folosesc HTML Canvas pentru desenarea link-urilor, şi un web-worker pentru pre-calcularea valorilor din simulare, dar nu am observat o creştere substanţială în performanţă.

O metodă care a funcţionat a fost rularea unui script pe back-end folosind Node.js pentru a pre-calcula valorile din simulare si a genera codul SVG pentru diagramă. Apoi am injectat SVG-ului în fişierul JavaScript, am legat din nou datele de SVG şi am făcut selecţiile D3.js să funcţioneze din nou. O abordare mai bună ar fi să migrez către o aplicaţie Node.js, şi să testez stream-urile Node.js (metode de manevrare a datelor folosite pentru a citi sau a scrie ce intră în ce iese în mod secvenţial).

Altă metodă ar fi să folosesc WebGL pentru a genera diagrama, deoarece este foarte bun la randarea unui număr mare de elemente în canvas, apoi să găsesc o cale prin care să evidenţiez interacţiunile din JavaScript.

Ce ar mai fi de făcut

  • Teste unitare
  • WebGL pentru a îmbunătăţi performanţa
  • Mutarea codului duplicat într-o bibliotecă comună
  • Afişarea unui tabel sortabil pentru cazurile cu legătură, cu zoom pe nod la selectare
  • Migrarea către o aplicaţie Node.js şi folosirea stream-urilor
  • Panou de control (dashboard) care să conţină toate graficele
  • Poveste bazată pe scroll (scroll-driven story) care să conţină toate graficele

COVID-19 în România – Posibile focare pe județe

Sursa de date: https://covid19.geo-spatial.org/api/statistics/getCaseRelations
Geometriile: http://geoportal.ancpi.ro/portal/apps/webappviewer/index.html?id=faeba2d173374445b1f13512bd477bb2
Codul: https://github.com/alexaac/covid-19-ro-cases-pack
Live: https://maptheclouds.com/covid-19-ro/cases-pack/en/ / https://covid19.geo-spatial.org/statistici/relationare-cazuri?chart=covid-19-ro-cases-pack
Tip: map + circle pack

De ce am făcut acest grafic?

Am vrut să văd cum sunt distribuite aglomerările de cazuri pe hartă, şi, pentru a îmbunătăţi vizibilitatea, am agregat punctele în funcţie de cazul sursă. De fapt, sunt două vizualizări, una reprezentând grupările pe hartă, şi alta reprezentând o împachetare mare a tuturor judeţelor.

Detalii de implementare

Am convertit fişierul cu geometriile judeţelor în GeoJSON folosind ‘Convert Format’ din GDAL (în QGIS), apoi am folosit Mapshaper să simplific fișierele GeoJSON, și să grupez toate datele într-un singur fișier TopoJSON. Acest format reduce mărimea fișierelor și are și alte funcții utile, cum ar fi topology-preserving shape simplification.

TopoJSON este o extensie a GeoJSON care codifică topologia. În loc să reprezinte geometriile discret, geometriile din fişierele TopoJSON sunt generate împreună din segmente de linie comune numite arcuri. (src)

Apoi, punctele care reprezintă datele agregate au fost dispuse circular peste fiecare judeţ, folosind o tehnică numită pack layout, care subdivide recursiv suprafaţa în cercuri proporţionale.

Împachetarea cercurilor (Circle Packing), cunoscută şi sub numele de Hartă Arborescentă Circulară (Circular Treemap), este o variantă de Treemap care foloseşte cercuri în loc de dreptunghiuri. Încadrarea în fiecare cerc reprezintă un nivel în ierarhie: fiecare ramură a copacului este reprezentată ca un cerc, iar subramurile sunt reprezentate ca cercuri în interiorul său. Aria fiecărui cerc poate fi folosită de asemenea pentru a reprezenta o valoare adiţională arbitrară, cum ar fi cantitatea sau mărimea fişierului. Şi culoarea poate fi folosită pentru a atribui categorii sau a reprezenta altă variabilă prin tonuri diferite. (src)


Ce ar mai fi de făcut

  • Teste unitare
  • Mutarea codului duplicat într-o bibliotecă comună
  • Animarea unei structuri de forţe deasupra fiecărui judeţ

COVID-19 în România – Relațiile dintre cazuri în timp

Sursa de date: https://covid19.geo-spatial.org/api/statistics/getCaseRelations
Codul: https://github.com/alexaac/covid-19-ro-cases-timeline
Live: https://maptheclouds.com/covid-19-ro/cases-timeline/en/ / https://covid19.geo-spatial.org/statistici/relationare-cazuri?chart=covid-19-ro-cases-timeline
Tip: arc diagram + bubble chart

De ce am făcut acest grafic?

M-am gândit că ar fi mai uşor de observat cât timp a durat până a fost confirmat următorul caz legat, de la apariţia unui caz sursă, şi cum au fost legate cazurile de-a lungul timpului.

Detalii de implementare

Aş fi putut folosi un force layout, şi să distribui punctele folosind un atribut numit forceX, dar din considerente de performanţă am folosit direct atributul zi pentru a desena punctele pe axa X, un atribut calculat ordinea pe zi pentru axa Y, şi numărul de cazuri legate pentru diametrul cercului, iar rezultatul a fost o diagramă cu bule (bubble chart).

O Diagramă cu Bule (Bubble Chart) este un graf multi-variabil care reprezintă o intersectare a unei Diagrame de corelaţie (Scatterplot) cu o Diagramă de arie proporţională (Proportional Area Chart). Ca şi diagrama de corelaţie, diagramele cu bule folosesc un sistem de coordonate cartezian pentru a trasa puncte de-a lungul unei grile unde axa X şi axa Y sunt variabile separate. Totuşi, spre deosebire de o diagrama de corelaţie, fiecărui punct îi este atribuită o etichetă sau categorie (fie afişată lângă, sau pe o legendă). Fiecare punct trasat reprezintă atunci o a treia variabilă prin aria cercului său. Şi culorile pot fi folosite pentru a reprezenta o variabilă adiţională a datelor. Timpul poate fi afişat fie ca o variabilă pe una dintre axe sau prin animarea schimbărilor variabilelor de date de-a lungul timpului. (src)

De asemenea am folosit reprezentarea printr-o diagramă arc (arc diagram) pentru legături.

Diagramele arc (Arc Diagrams) sunt o metodă alternativă de reprezentare a diagramelor de reţea bidimensionale. În diagramele arc, nodurile sunt plasate de-a lungul unei singure linii (o axă unidimensională) iar arcurile sunt folosite pentru a arăta conexiunile dintre aceste noduri. (src)

Ce ar mai fi de făcut

  • Teste unitare
  • Mutarea codului duplicat într-o bibliotecă comună

COVID-19 în România – Cazuri pe județe

Sursa de date: https://covid19.geo-spatial.org/api/dashboard/v2/getCasesByCounty
Codul: https://github.com/alexaac/covid-19-ro-cases-treemap
Live: https://maptheclouds.com/covid-19-ro/cases-treemap/ / https://covid19.geo-spatial.org/statistici/repartitie-cazuri-judete
Tip: treemap

De ce am făcut acest grafic?

Am vrut să scot în evidenţă judeţele cu numărul cel mai mare de cazuri confirmate, aşa că am afişat judeţele ordonate după numărul de cazuri.

Detalii de implementare

Am folosit un treemap, care subdivide recursiv suprafaţa în dreptunghiuri, şi am atribuit o culoare unică fiecărui judeţ.

Treemap-urile reprezintă o metodă alternativă de vizualizare a structurii ierarhice a unei diagrame arborescente (Tree Diagram) în timp ce de asemenea afişează cantităţi pentru fiecare categorie prin intermediul mărimii suprafeţei. Fiecărei categorii îi este atribuită o suprafaţă rectangulară care are imbricate dreptunghiurile de subcategorii. Când o cantitate este atribuită unei categorii, mărimea suprafeţei sale este afişată proporţional cu acea cantitate şi cu celelalte cantităţi dinăuntrul aceleiaşi categorii părinte, într-o relaţie parte-întreg. De asemenea, mărimea suprafeţei categoriei părinte reprezintă totalul subcategoriilor sale. Dacă unei subcategorii nu îi este atribuită nicio cantitate, atunci suprafaţa este împărţită în mod egal între celelalte subcategorii din cadrul categoriei ei părinte. (src)

Apoi, am ales o paletă de culoare generată pe iwanthue, folosind următoarele setări:

// https://medialab.github.io/iwanthue/
// hcl[0]>=0 && hcl[0]<=340
//     && hcl[1]>=30 && hcl[1]<=80
//     && hcl[2]>=35 && hcl[2]<=100

Ce ar mai fi de făcut

  • Teste unitare
  • Diferite scheme de culori

COVID-19 în România – Relațiile dintre cazuri, pe județe

Sursa de date: https://covid19.geo-spatial.org/api/statistics/getCaseRelations
Codul: https://github.com/alexaac/covid-19-ro-cases-counties
Live: https://maptheclouds.com/covid-19-ro/cases-counties/en/
Tip: network diagram

Aceasta este o variantă a graficului ‘Relațiile dintre cazuri’, în care cazurile sunt grupate după judeţ şi cazul sursă.

Asta a fost tot. Mulţumesc din nou, geo-spatial.org, pentru iniţiativă. 🤗

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *