Created on 16 May 2020 ;    Modified on 16 May 2020

Confrontare serie temporali dell'infezione da Coronavirus Covid-19

Chi ha l'occhio allenato, e ha visitato il mio sito più di un volta, avrà notato che nel menù vi è una voce in più, che rimanda ad una sezione per confrontare graficamente i dati dell'infezione di Covid-19. Questo lavoro è nato quasi per gioco: uno dei miei fratelli mi ha chiesto se era possibile confrontare gli andamenti dei casi di infezione per nazioni diverse ...

Premessa

... e quest'idea ha continuato a mulinarmi in mente. Dopo di che, con la mia solita guasconeria, ho pronunciato la storica frase: "... e che ci vuole?" ...

... "Ci vuole, ... ci vuole, ...": alcune (poche) settimane di lavoro a tempo parziale, tanta buona volontà, e la testardaggine per non lasciarsi scoraggiare dagli inevitabili intoppi che si troveranno lungo il cammino.

L'organizzazione generale

Cominciamo con le decisioni strategiche.

Il linguaggio di base da utilizzare non è una decisione:-) Python. Non si discute.

Poi, la libreria di grafica. In Python mathplotlib è una delle più diffuse: usiamo questa.

Dopo di che la gestione dei dati. Ci serve uno strumento flessibile, con cui elaborare (rapidamente) i dati in forma matriciale e che si adatti bene a mathplotlib (o viceversa: dipende da come la si vede). Direi che pandas possa fare al caso nostro. È un ottimo strumento di data analysis, anche se a volte ci faccio a botte.

Quindi il framework di sviluppo web. Il solito Django? No, questa volta direi di no. Per due motivi. Il primo è che vogliamo provare qualcosa di nuovo. Il secondo è che in questo caso non abbiamo base dati, nè necessità di gestire account utente. Tanto vale usare un microframework, come ad esempio flask.

E i dati da dove li peschiamo? Dal sito dell'European CDC, che già conosciamo, in quanto è la fonte dei dati con cui alimentiamo il nostro articolo riguardo l'andamento temporale del Coronavirus Covid-19 nel mondo. Questa organizzazione finora si è dimostrata affidabile: aggiorna i dati regolarmente [1].

Ultima decisione importante: il sistema di version control. Per un piccolo progetto, come questo, può sembrare esagerato. Ma non è così. Utilizzando il solito git e l'infrastruttura web GitHub, abbiamo a disposizione uno strumento che ci permette:

  • di recuperare in sicurezza eventuali errori estesi a più file,
  • condividere il progetto tramite un repository distribuito.

Di conseguenza questo progetto è pubblicato all'indirizzo GitHub: https://github.com/l-dfa/flask_covid.

La struttura del sito

Definiti gli strumenti, che struttura dare al sito? Farne uno completamente nuovo ci è sembrato fuor di luogo, anche perché si tratta di:

  • selezionare le scelte dell'utente riguardo quali nazioni confrontare;
  • e visualizzare il relativo risultato;
  • eventualmente slittare le curve per poterle confrontare.

Se aggiungiamo una pagina di benvenuto, stiamo parlando di quattro pagine web. In realtà tre, in quanto il grafico, sovrapposto o meno, lo possiamo tracciare sulla stessa pagina.

Quindi sviluppiamo una sezione del nostro blog, con un apposito dominio di terzo livello. Costruiremo la sezione covid in https://covid.defalcoalfano.it.

Qui dobbiamo prendere una decisione: sarebbe bene avere un layout uguale a quello del blog, ovvero con lo stesso menù. Ma ottenere questo risultato è troppo complesso perché parte di quel menù è derivato dinamicamente dal database del blog. Database gestito tramite Django. Tutto è possibile, ma decisamente l'effort non si giustifica. Scegliamo una strada di compromesso: utilizziamo, come nel blog, boostrap e il relativo css di base, ma facciamo un menù ad hoc. In tal modo il layout è uguale, salvo le voci del menù: un sacrificio accettabile.

La struttura dell'applicazione

Come sviluppare una applicazione Flask è riportato in diversi tutorial. Ci siamo appoggiati inizialmente al mega-tutorial di Miguel Grinberg perchè ha un avvio più dolce del tutorial ufficiale di Flask.

Per una applicazione semplice come la nostra, ci bastano:

  • un paio di file di configurazione (config.py e covid.py);
  • un file di istanziazione dell'applicazione Flask (covid/__init__.py) in cui infiliamo anche un paio di strutture dati di carattere generale;
  • un file di gestione degli indirizzi da servire (covid/routes.py), in cui mettiamo anche la logica applicativa;
  • un file di definizione (parziale) della form di interfaccia verso l'utente (covid/forms.py);
  • un file ausiliario (covid/errors.py) per la gestione delle condizioni d'errore.

Il coding è tutto qui. Il grosso sono le circa 650 righe di covid/routes.py in cui è implementata la logica applicativa. Commenti inclusi.

Le pagine WEB

La costruzione delle pagine web passa attraverso il solito meccanismo dei template. Di default Flask utilizza Jinja 2 come motore di templating. Questo è molto simile al motore di templating adottato da Django, anche se in alcuni casi è più potente.

Quindi dobbiamo scrivere quattro pagine html, con qualche estensione:

  • una struttura di base, su cui innestare le altre sezioni (covid/templates/base.html); questa sviluppa la struttura di base del documento html: head e body;
  • la sezione del menù (covid/templates/navbar.html);
  • la sezione ausiliaria piè di pagina (covid/templates/footer.html);
  • ed infine le tre sezioni principali, che danno corpo alle tre pagine dell'applicazione:
    • la home della sezione che stiamo sviluppando (covid/templates/index.html);
    • la form di interfaccia per le scelte dell'utente (covid/templates/select.html);
    • la pagina che visualizza i grafici (covid/templates/plot.html).

Le lingue

Come sappiamo, la lingua del WEB è l'inglese. D'altro canto noi ci troviamo più a nostro agio con l'italiano. Quindi, complichiamoci la vita sviluppando il sito in modalità bilingue.

A questo fine il tutorial di Grinberg è lineare, si segue facilmente e si implementa altrettanto facilmente. Anche se ci si deve abituare alla necessità di attuare più step e di rendere più complesso sia il codice che i template.

Il metodo utilizzato da Grinberg è molto elegante perché adatta la risposta dell'applicazione alla configurazione del browser utente. Però vi è uno (grosso) svantaggio: Google per classificare una pagina con un linguaggio, ha bisogno di un indirizzo che la punti [2]; e qui, purtroppo, abbiamo un indirizzo solo.

Personalmente, abbiamo adottato il metodo Grinberg, anche se ci svantaggia rispetto Google. Per futuri siti sviluppati con Flask, mi riprometto di rivedere questo aspetto per implementare lo schema di Django, che suggerisce l'uso di URL multiple: una per lingua.

La messa in produzione

Per la messa in produzione, i problemi, e le attività da effettuare, sono le stesse affrontate con Django.

Per grandi linee:

  • copia dell'applicazione sul file system del server;
  • configurazione del server http che fa da reverse proxy (nel nostro caso Nginx);
  • configurazione del servizio http locale con Gunicorn.

Un'ultimo aspetto: l'aggiornamento dei dati da utilizzare deve essere giornaliero. Obbligatoria la scrittura di uno script Bash (get_covid_data.sh) che scarichi dal sito dell'agenzia Europea CDC il file csv che ci interessa. Configureremo crontab per eseguire lo script predetto alle 13:15 di tutti i giorni, visto che ECDC aggiorna i dati alle 12:00.

Enjoi


[1]

In un paio di mesi solo due volte non ha aggiornato i dati in formato csv. Per contro li ha sempre aggiornati in formato xls, da cui, per quelle due volte ho derivato il csv relativo.

Aggiornamento: oggi, 16 mag 2020, sono incorsi in un curioso problema. Il file csv non è stato aggiornato. Il file xls è stato aggiornato, ma il suo contenuto è quello del file csv. Scherzi dell'informatica :-) Comunque nulla di irrimediabile: è bastato fare un cut & paste verso un editor di file e salvare dall'editor.

[2]

Ad esempio, se ho una pagina http://dominio.com/home.html con due linguaggi, per farla classificare a Google con le due diverse lingue dovremo sottoporre al motore di ricerca due URL. Ad esempio, spesso di usa un pattern di questo tipo:

per indirizzare la pagina in inglese e quella in italiano. Con la metodologia esposta da Grinberg, l'indirizzo è unico: l'uscita dell'applicazione si adatta dinamicamente alla configurazione del browser. Di conseguenza in questo caso il bot di Google vedrà la pagina con la lingua di riferimento (ad es. l'inglese), e ignorerà la presenza di quella scritta in italiano.