• Non ci sono risultati.

Web based graph library

N/A
N/A
Protected

Academic year: 2021

Condividi "Web based graph library"

Copied!
76
0
0

Testo completo

(1)

Studente/i

Olmo Barberis

Relatore

Nicola Rizzo

Correlatore

Francesca Faraci

Committente

SUPSI

Corso di laurea

Ingegneria Informatica

Modulo

M00009 Lavoro di Diploma

Anno

2019

Data

30 agosto 2019

(2)
(3)

Questo lavoro viene sottomesso a parziale requisito per il conseguimento del

BACHELOR IN INGEGNERIA INFORMATICA

SCUOLA UNIVERSITARIA PROFESSIONALE DELLA SVIZZERA ITALIANA

DIPARTIMENTO TECNOLOGIE INNOVATIVE MANNO, SVIZZERA

(4)
(5)

Indice

Abstract 1

Introduzione 3

1 Motivazione e Contesto 5

1.1 Contesto . . . 6

1.1.1 Disturbi del sonno . . . 6

1.1.2 Polisonnografia . . . 6

1.1.3 Scoring di una polisonnografia . . . 7

1.2 Motivazione . . . 7

2 Problema 9 2.1 Dati . . . 10

2.1.1 Raccolta dei dati . . . 10

2.1.1.1 Formato EDF+ . . . 10

2.1.2 Caricamento dei dati . . . 10

2.1.3 Rappresentazione dei dati . . . 11

2.2 Discrepanze tra grafici . . . 12

3 Embla RRemlogicTM 15 3.1 Esperienza d’uso . . . 16 3.1.1 Finestra di visualizzazione . . . 17 3.1.2 Menu eventi . . . 17 3.1.3 Annotazioni . . . 17 3.1.4 Funzionalità e Criticità . . . 18 4 Approccio 19 4.1 Strumenti . . . 20

4.1.1 Spring, Spring MVC Spring Boot, Spring Data . . . 20

4.1.2 MySQL . . . 21

4.1.3 Thymeleaf . . . 21

4.1.4 JUnit . . . 21

(6)

4.1.5 Mockito . . . 21

4.1.6 Node.js e Node Package Manager . . . 21

4.1.7 Webpack . . . 21 4.1.8 Sortable.js . . . 22 4.1.9 Karma e Jasmine . . . 22 4.1.10 Fontawesome . . . 22 4.1.11 Coreui . . . 22 4.1.12 Echarts . . . 22

4.2 Pianificazione del lavoro . . . 22

5 Risultati 25 5.1 Server . . . 26 5.1.1 Database . . . 26 5.1.2 Struttura Classi . . . 27 5.1.2.1 EDFParser . . . 27 5.1.3 Downsampler . . . 27 5.1.3.1 Confronto Downsampler . . . 28 5.1.3.2 Controller . . . 29

5.2 Libreria per grafici . . . 32

5.2.1 Echarts . . . 32 5.2.1.1 Grid . . . 32 5.2.1.2 Series . . . 32 5.2.1.3 xAxis . . . 33 5.2.1.4 yAxis . . . 34 5.2.1.5 Brush . . . 34 5.2.1.6 DataZoom . . . 35 5.2.1.7 markLine . . . 35 5.2.1.8 markPoint . . . 36 5.2.1.9 markArea . . . 37 5.2.2 Astrazione di echarts . . . 37 5.2.2.1 Pubsub . . . 37 5.2.2.2 Dom . . . 37 5.2.2.3 OptionsBuilder . . . 38 5.2.2.4 NotesBuilder . . . 39 5.2.2.5 EventNotificator . . . 39 5.2.2.6 Chart . . . 39 5.3 Interfaccia Grafica . . . 42 5.3.1 JavaScript . . . 48 5.3.1.1 Settings . . . 48 5.3.1.2 AnnotationsAsideMenu . . . 49

(7)

5.3.1.3 AnnotationsManager . . . 49 5.3.1.4 CustomEventManager . . . 50 5.3.1.5 Hypnogram . . . 50 5.3.1.6 PatientsHandler . . . 51 5.3.1.7 RecordingsHandler . . . 52 5.3.1.8 SidebarManager . . . 53 5.3.1.9 Colors . . . 53 5.3.1.10 ContextMenu . . . 53 5.3.1.11 DataChanger . . . 54 5.3.1.12 Viewport . . . 54 5.3.1.13 FileUploader . . . 55 5.3.1.14 Network . . . 55 5.3.1.15 TracesModal . . . 56 5.3.1.16 ChartsManager . . . 56 5.3.1.17 Punto di accesso . . . 58 6 Conclusione 61 6.1 Confronto con lo stato dell’arte . . . 62

6.2 Limiti . . . 63

6.3 Sviluppi futuri . . . 63

6.4 Considerazioni Personali . . . 64

(8)
(9)

Elenco delle figure

2.1 EKG - 30s con Remlogic . . . 12

2.2 EKG - 30s con la libreria JavaScript . . . 12

2.3 EKG - 30s con Polyman . . . 13

3.1 UI di Remlogic dopo il caricamento di Workpad . . . 16

3.2 Sezione in cui è possibile modificare la finestra temporale . . . 17

3.3 Dettaglio di alcune note . . . 18

5.1 Confronto tra Downsampler . . . 28

5.2 Esempio di un oggetto grid . . . 32

5.3 Esempio di un oggetto series . . . 33

5.4 Esempio di un oggetto xAxis . . . 33

5.5 Esempio di un oggetto yAxis . . . 34

5.6 Esempio di un oggetto brush . . . 34

5.7 Esempio di un oggetto DataZoom . . . 35

5.8 Grafico con due componenti markLine . . . 36

5.9 Grafico con tre markPoint . . . 36

5.10 Pagina web iniziale . . . 42

5.11 Finestra di dialogo per l’upload di una nuova registrazione . . . 43

5.12 Finestra di gestione delle registrazioni . . . 44

5.13 Finestra di dialogo per caricare i canali . . . 44

45 5.15 Dettaglio di un grafico con menù contestuale . . . 46

5.16 Sezione della finestra Patients . . . 46

5.17 Form per la creazione di un paziente . . . 47

5.18 Form per la modifica del paziente . . . 47

5.19 Modulo Settings . . . 48

(10)
(11)

Abstract

Lo scopo di questo progetto è di creare un sistema che consenta di visualizzare, sotto forma di grafici, dei dati raccolti durante una polisonnografia, ovvero la registrazione tramite dei sensori di vari segnali fisiologici durante una notte di sonno. L’analisidei grafici permette di estrarre alcune informazioni le quali sono utilizzate per effettuare uno scoring del sonno. Lo scoring del sonno è una procedura atta a identificare in quale fase del sonno il paziente si trova. Si dovrà inoltre poter aggiungere delle annotazioni ai grafici visualizzati. All’interno del progetto si dovrà implementare un software come libreria, riutilizzabile in altri contesti per visualizzare ed annotare grafici.

The aim of this project is to create a system that allows the user to view, in the form of graphs, the data collected during a polysomnography, which is the recording by sensors of various physiological signals during a night’s sleep. The graphs are analyzed and certain informations are extracted, which are used to perform a sleep scoring. Sleep scoring is a procedure for identifying at which stage of sleep the patient is.

It will also be necessary to be able to add annotations to the graphs displayed and to perform scoring. Within the project it will be required to implement a software as a library, reusable in other contexts to view and annotate graphs.

(12)
(13)

Introduzione

Nel Capitolo 1 sono introdotti il contesto e la motivazione che hanno portato allo svolgimento di questo progetto. In particolar modo è descritto cosa sono i disturbi del sonno, che con-seguenze hanno e cos’è una polisonnografia, ovvero lo strumento principale attualmente utilizzato per diagnosticar i disturbi del sonno.

Inoltre sono spiegate quali sono le esigenze che hanno portato a implementare un sistema server-interfaccia grafica per effettuare l’analisi del sonno.

Nel Capitolo 2 si analizzano le criticità e le difficoltà relative alla raccolta e all’analisi dei dati raccolti dalle polisonnografie. Si spiega quali sono le difficoltà nel gestire grandi quantità di dati e quali possibili soluzioni bisognerebbe implementare. Nella parte finale si analizza una discrepanza tra i grafici di un software commerciali e quelli ottenuti tramite il sistema sviluppato da questo progetto.

L’analisi dello stato dell’arte avviene nel capitolo 3, in cui si analizza l’esperienza d’uso of-ferta da un software commerciale per la diagnostica del sonno, evidenziando le funzionalità e le criticità.

Le tecnologie scelte, la pianificazione del lavoro e come si è deciso di implementare il siste-ma vengono spiegati nel Capitolo 4.

Il Capitolo 5 è dedicato all’illustrazione dei risultati raggiunti. Viene spiegato come funziona il sistema, le particolarità del server e del database, come è stata sviluppata l’interfaccia grafica e la libreria per l’annotazione e la visualizzazione dei grafici.

Infine, nel Capitolo 6, si effettua un confronto tra le funzionalità e l’esperienza d’uso del sistema implementato con un software commerciale. Inoltre sono presentati i principali problemi conosciuti così come alcuni possibili sviluppi futuri.

(14)
(15)

Capitolo 1

Motivazione e Contesto

(16)

1.1

Contesto

1.1.1

Disturbi del sonno

I disturbi del sonno costituiscono un problema di salute diffuso e in costante crescita. Rap-presentano un gruppo di patologie che alterano il normale ciclo di sonno e di veglia e cau-sano ripercussioni sulle attività diurne. Ad esempio, in Svizzera un infortunio sul lavoro su cinque è dovuto a disturbi del sonno[1]. Circa il 10% della popolazione soffre di disturbi cro-nici del sonno e questo ha delle conseguenze che includono problemi di memoria, pressione alta, malattie cardiache, attacchi di sonno, diabete, depressioni e fobie[2].

1.1.2

Polisonnografia

Il principale strumento per valutare la qualità del sonno ed identificarne eventuali problemi è la polisonnografia. È un termine che indica la registrazione di vari segnali fisiologici durante una notte, durante la quale un soggetto viene monitorato con numerosi sensori al fine di raccogliere dati per analizzare la sua qualità del sonno.[3]

Vi sono vari segnali monitorati, come ad esempio:

• L’elettroencefalogramma (EEG) - Registrazione dell’attività dell’encefalo: serve per determinare il profilo del sonno (ipnogramma)

• L’elettrocardiogramma (ECG) - Monitoraggio dell’attività cardiaca: serve per eviden-ziare anomalie cardiache legate ai disturbi respiratori del sonno

• L’elettrooculogramma (EOG) - Individua il movimento degli occhi durante il sonno: serve a distinguere le fasi di sonno REM e ad individuare eventuali apnee notturne

• L’elettromiografia (EMG) - Monitora l’attività del sistema nervoso periferico e le attività motorie durante il sonno

Al termine della polisonnografia i dati vengono elaborati e mostrati sotto forma di grafici. In seguito viene eseguita una procedura di scoring del sonno, durante la quale uno specialista esamina i dati registrati e identifica alcuni eventi come:

• Fasi del sonno - Esistono 5 fasi di sonno che avvengono all’interno di un intero ciclo

• Risvegli durante la notte

• Attività respiratorie

• Movimenti

(17)

1.1.3

Scoring di una polisonnografia

Lo scoring di una polisonnografia è il processo di estrazione di informazioni riguardanti i cicli del sonno dai grafici. Questo processo è un lavoro lento che richiede l’analisi di EEG, EOG e EMG da parte di uno specialista e una notte di 8 ore può richiedere fino a due ore di tempo per essere analizzata. Purtroppo oggigiorno non ci sono ancora strumenti che consentano lo scoring automatico, nonostante i primi lavori per automatizzare il processo siano iniziati alla fine degli anni ’60.

Lo scoring avviene analizzando epoche di 30 secondi di sonno a partire dal momento in cui vengono spente le luci. Si effettua un’analisi visuale del grafico e si assegna uno dei possibili 5 stadi del sonno: W (sveglio), N1, N2, N3 e R (REM) . Per identificare in quale stage del sonno ci si trova esistono delle linee guida edite dall’American Academy of Sleep Medicine1, in cui si descrive quali eventi o pattern indicano uno stadio del sonno. È possi-bile creare solamente delle linee guida perché vi sono troppe differenze tra il sonno di vari individui per poter avere dei comportamenti comuni al fine di creare un regolamento preci-so e puntuale. Per questo motivo il risultato dello scoring di una polipreci-sonnografia dipende dall’analisi soggettiva dello specialista che lo esegue.

La procedura risulta comunque parecchio complicata, bisogna verificare molti parametri contemporaneamente e controllare la finestra precedente e successiva per identificare cor-rettamente lo stadio del sonno. Inoltre l’etereogeneità dei soggetti da controllare, l’impatto di eventuali specifici disturbi del sonno e la presenza di altre anomalie rende ancora più complesso effettuare lo scoring e aumenta le discrepanze tra i risultati di diversi specialisti.

1.2

Motivazione

Lo scopo di questo progetto è di creare un sistema che possa essere uno strumento com-plementare ed integrabile con i software professionali attualmente utilizzati.

Questo sistema deve poter offrire un’interfaccia grafica integrata in una piattaforma web preesistente dalla quale analizzare e valutare i dati. In questo modo non sarà necessario installare su ogni dispositivo utilizzato il software e sarà possibile effettuare l’analisi delle registrazioni da qualsiasi piattaforma e dispositivo, senza alcun limite legato all’hardware o al sistema operativo della macchina da cui si opera.

Un server di backend deve permettere di creare e amministrare una serie di pazienti, con-servando in database le informazioni di ognuno, e i loro dati raccolti tramite polisonnografie. Si devono poter caricare molteplici registrazioni per ogni paziente.

1

AASM, https://aasm.org/

(18)

Tramite l’interfaccia grafica, sviluppata con tecnologie web, deve essere possibile gestire una lista di pazienti registrati salvati nel server di backend. Per ogni paziente deve essere possibile caricare delle polisonnografie e rappresentarle in forma grafica. Inoltre si dovrà poter aggiungere e visualizzare delle annotazioni.

Inoltre l’interfaccia, per disegnare i grafici, deve sfruttare una libreria JavaScript sviluppata ex novo, riutilizzabile in altri contesti, che consenta di visualizzare qualsiasi tipo di diagramma e di aggiungere annotazioni direttamente sul grafico.

Nel contesto di questo lavoro di diploma in particolar modo si richiedeva di:

• Sviluppare una piattaforma web che offrisse le seguenti funzionalità:

– Essere accessibile da qualsiasi dispositivo con qualsiasi sistema operativo senza

nessuna installazione

– Visualizzare e gestire una serie di pazienti, conservando in un database le

sin-gole informazioni e i dati delle loro polisonnografie

– Visualizzare una parte o tutti i dati raccolti da una polisonnografia, consentendo

la scelta di quali canali e di quale lasso di tempo visualizzare, disegnando un grafico per ogni canale. Sui grafici si deve poter avere le seguenti funzionalità:

∗ Zoom in e out della porzione di dati caricati su tutti i grafici in contemporanea

∗ Caricamento di una nuova finestra di dati da tastiera premendo le frecce direzionali

∗ Menù opzioni che consenta di personalizzare i colori di ogni grafico

∗ Drag and drop dei grafici in modo da poter modificare l’ordinamento nella UI

– Visualizzare un grafico dello scoring dei dati di ogni registrazione – Visualizzare tutti gli eventi e le annotazioni di ogni registrazione – Annotare ed aggiungere eventi di qualsiasi durata su uno o più grafici

• Sviluppare una libreria JavaScript che consenta l’annotazione di un grafico generico

(19)

Capitolo 2

Problema

(20)

2.1

Dati

2.1.1

Raccolta dei dati

Una notte di registrazioni comporta la raccolta di una grande quantità di dati. Al soggetto da monitorare si possono applicare fino ad una cinquantina di sensori i quali raccolgono informazioni con una frequenza di campionamento che può variare tra 60 e 200 Hz. Una frequenza di campionamento di 200 Hz significa che vengono salvati 200 valori ogni secon-do, che equivalgono a 5’760’000 di punti per 8 ore di registrazione per un solo paziente. Da un software per effettuare l’analisi e la diagnostica del sonno, ad esempio Remlogic, si può esportare un file in formato EDF, che contiene tutti dati del paziente, le informazioni sulla registrazione e tutti i valori registrati di tutti i canali.

2.1.1.1 Formato EDF+

Il formato EDF+ è uno formato di file standard, open e non proprietario, utilizzato per ar-chiviare, scambiare e analizzare dati di elettroencefalogrammi e polisonnografie. È basato sul formato EDF (introdotto nel 1992), con il quale mantiene completa compatibilità, ed è formato da un header seguito dai dati registrati. L’header del file contiene i dati che indetifi-cano il paziente e tutte le caratteristiche tecniche dei canali registrati. Tra le informazioni più importanti da estrarre si trovano:

• ID del paziente

• Giorno di inizio della registrazione

• Orario di inizio della registrazione (HH:mm:ss)

• Numero di canali

• Lista dei label dei canali

All’interno del file EDF dopo l’header troviamo tutti i valori registrati da tutti i canali.

2.1.2

Caricamento dei dati

Il file EDF contente tutte le informazioni dovrà essere caricate e persistite all’interno del server. Le informazioni contenute nell’header dovranno essere salvate all’interno di strutture dati in un database, mentre non è consigliato salvare i dati delle registrazioni direttamente sul DB. Salvare file binari di grosse dimensioni direttamente sul database comporterebbe un aumento eccessivo delle dimensioni di quest’ultimo e ne diminuirebbe le performance,

(21)

sia durante le normali operazioni di lettura e scrittura sia in caso di backup e recupero dei dati.

Perciò i dati saranno estratti dal file EDF, convertiti in un formato facilmente leggibile dal ser-ver ed in seguito salvati sotto forma di file binario direttamente nel file system, mantenendo un riferimento al file nel server. In questo modo si potranno garantire delle performance maggiori in fase di caricamento dei dati, migliorando la reattività generale del sistema.

2.1.3

Rappresentazione dei dati

Una volta estratti i dati essi devono venire serviti dal server all’interfaccia grafica. Questo processo presenta però numerose problematiche legate alla grande quantità di dati da ela-borare.

Lo scoring della polisonnografia normalmente prevede che lo specialista lavori con finestre temporali limitate. Egli osserva 30/40 secondi di registrazione di un numero di canali che varia da 6 (minimo consigliato dalle linee guida) a 9. 40 secondi di registrazione a 200 Hz corrisponde a 8’000 punti per ogni grafico.

La rappresentazione di un grafico avviene su schermi che hanno una quantità limitata di pixel. Supponendo di utilizzare una risoluzione FullHD (1920 x 1080 pixel) e lavorare con delle barre laterali in cui sono presenti strumenti e altre informazioni utili allo scoring, non si avranno più di 1500 pixel per rappresentare 8000 punti. Al fine di velocizzare la rappresen-tazione dei dati è quindi necessario effettuare un sottocampionamento dei valori lato server, in modo da poter servire alla libreria che renderizza i dati in grafici un quantitativo adatto di coordinate limitandone il lavoro di sottocampionamento. Inoltre l’invio di una quantità mino-re di dati consente di avemino-re velocità di trasferimento più elevate tra frontend e backend e di diminuire il carico generale della rete.

È necessario trovare un metodo di sottocampionamento che consenta di ottenere perfor-mance di alto livello mantenendo un’adeguata coerenza visiva tra i dati originali e i dati sottocampionati.

(22)

2.2

Discrepanze tra grafici

È stata riscontrata una discrepanza tra i grafici visualizzati su Remlogic e quelli prodotti partendo da un file .edf.

Figura 2.1: EKG - 30s con Remlogic

Nella figura 2.1 si può vedere il grafico di un canale EKG1 come mostrato sul software Remlogic.

Figura 2.2: EKG - 30s con la libreria JavaScript

Un file EDF contenente il canale mostrato in figura 2.1 è stato generato tramite Remlogic e, dopo aver estratto i dati, è stato generato un grafico con la libreria echarts. Il grafico risultante è mostrato nella figura 2.2 ed utilizza gli stessi dati della figura 2.1

Visivamente si possono notare delle differenze tra i due grafici, in particolar modo nella fase iniziale vi è un picco nel grafico Remlogic che è assente in quello della figura 2.2, mentre in quest’ultimo è presente un picco negativo assente nel grafico Remlogic. Inoltre in echarts il grafico sembra avere dei valori troncati, mentre in Remlogic il picco massimo raggiunge valori più alti. Esaminando il file EDF si nota come i valori massimi riscontrati siano coerenti con il disegno del grafico, mentre non è stato possibile ricavare il valore dei dati grezzi di Remlogic.

Per verificare la correttezza del grafico caricato in echarts si è provato a caricare il file edf in Polyman2, un software suggerito dal portale www.edfplus.info per la visualizzazione dei file EDF.

1Elettrocardiogramma 2

(23)

Figura 2.3: EKG - 30s con Polyman

Il grafico mostrato con Polyman, visibile nella figura 2.3 è assolutamente identico al grafico disegnato tramite la libreria sviluppata.

Aumentando lo zoom sul grafico di Remlogic è stato possibile visualizzare i valori di ogni punto, i quali sono sostanzialmente diversi dai valori contenuti nel file edf. Non è possibile sapere però se i punti visualizzati siano effettivamente i dati raccolti dai sensori o se siano dei valori sottocampionati da Remlogic.

Purtroppo non è stato possibile comprendere l’origine di queste discrepanze, non sapen-do se e quali eventuali filtri di sottocampionamento Remlogic applichi oppure se vi siano eventuali problemi di esportazione dei segnali in formato edf.

(24)
(25)

Capitolo 3

Embla

R

Remlogic

TM

(26)

3.1

Esperienza d’uso

Per lo svolgimento di questo lavoro si è considerato il software commerciale Embla R

Rem-logic come lo stato dell’arte a cui confrontarsi. Questo programma è uno dei più utilizzati al mondo per effettuare diagnostica delle polisonnografie.

In particolare ci si è ispirati alla versione 3.4.4 per sviluppare l’interfaccia in modo che for-nisse un’esperienza d’uso analoga. Questo consentirebbe di abbassare la curva di appren-dimento del sistema per gli operatori che utilizzano Remlogic.

L’interfaccia grafica del software consente di visualizzare una barra laterale in cui si ha una lista ad albero dei vari pazienti e delle loro registrazioni. Si possono caricare i dati di una registrazione effettuando un doppio click sul "Workpad" desiderato.

Figura 3.1: UI di Remlogic dopo il caricamento di Workpad

Nella figura 3.1 nella barra orizzontale sono presenti svariati comandi, mentre nella barra laterale sinistra è presente la lista di pazienti ed è possibile visualizzare per ogni paziente un Workpad della relativa polisonnografia. Dopo aver effettuato un doppio click su un Workpad i canali vengono caricati e si possono definire svariate finestre (in basso) per visualizzare i dati desiderati a seconda del bisogno.

(27)

3.1.1

Finestra di visualizzazione

Remlogic mostra una finestra di tempo di 30 secondi, che è la dimensione standard per ef-fettuare lo scoring delle polisonnografie. È possibile modificare la dimensione della finestra a piacimento premendo il tasto sinistro del mouse nella barra orizzontale in cui è segnalato l’orario ed effettuando un trascinamento verso destra (diminuire la finestra) o a sinistra.

Figura 3.2: Sezione in cui è possibile modificare la finestra temporale

Nella figura 3.2 il rettangolo rosso indica la sezione di interfaccia in cui si può modificare la dimensione della finestra

3.1.2

Menu eventi

Premendo uno dei bottoni della toolbar in alto è possibile attivare un menu legato agli eventi. In questo menu laterale è possibile:

• Visualizzare i comandi rapidi per aggiungere eventi

• Visualizzare gli eventi già presenti in ordine

• Visualizzare lo scoring effettuato

• Visualizzare altre note tecniche

3.1.3

Annotazioni

I grafici possono presentare annotazioni con una determinata durata oppure possono es-sere puntuali. Premendo la combinazione relativa ad un comando rapido è possibile ag-giungere eventi di una durata prefissata (es. 30 secondi) oppure istantanea. Questo varia a dipendenza di quale tipo di annotazione si sceglie di aggiungere. Inoltre è anche possibile aggiungere annotazioni di lunghezza personalizzata, selezionando una porzione di grafico

(28)

con il mouse e premendo il relativo comando sulla barra laterale o la combinazione di tasti ad essa associato.

Figura 3.3: Dettaglio di alcune note

Nella figura 3.3 è possibile vederne alcune. Nel primo grafico si possono visualizzare al-cuni rettangoli sovrapposti in cui è possibile aggiungere osservazioni personali, mentre nel quarto grafico dall’alto si può vedere un’annotazione "Apnea" della durata predefinita di 10 secondi ed una di una durata di 36.96 secondi realizzata selezionando la parte di grafico interessata. Nel penultimo grafico è invece presente un’annotazione senza durata "Apnea Arousal".

3.1.4

Funzionalità e Criticità

Generalmente l’interfaccia di Remlogic è sempre reattiva e non vi sono rallentamenti di sor-ta, tranne quando si espande la finestra di visualizzazione oltre i 15 min. In quel caso il caricamento e lo scroll dei dati avvengono lentamente e a scatti. Questa non è però una situazione di lavoro comune.

La visualizzazione delle note risulta problematica quando se ne hanno molte ravvicinate, come si può vedere nella figura 3.3 dove le note gialle sono sovrappose e poco leggibili. Inoltre l’inserimento del testo all’interno del grafico rende difficoltosa la lettura del grafico. Un altro limite di Remlogic è che deve venire installato su un dispositivo che abbia: sistema operativo Windows e in cui sia installato Office versione 2010 o successiva. Non è pertan-to possibile utilizzare il software su piattaforma MacOS o Linux e bisogna acquistare una licenza per ogni dispositivo su cui si intende installare il programma.

(29)

Capitolo 4

Approccio

(30)

4.1

Strumenti

Per implementare il sistema si è dapprima deciso quali tecnologie e strumenti fosse meglio utilizzare.

Server:

• Spring, Spring MVC Spring Boot, Spring Data

• MySQL

• Thymeleaf

• JUnit

• Mockito Interfaccia:

• Node.js, Node Package Manager

• Webpack • HTML5 , SCSS, JavaScript • Sortable.js • Karma e Jasmine • Fontawesome • Coreui Libreria: • JavaScript • echarts

4.1.1

Spring, Spring MVC Spring Boot, Spring Data

Spring è un framework che consente di sviluppare applicazioni complesse su piattaforma Java. Fornisce diverse funzionalità, come dependency injection, supporto per JPA e JDBC e molto altro. Sfruttando le funzionalità offerte da Spring, Spring MVC permette di realizzare applicazioni basate sul pattern MVC in modo semplice ed automatico.

Spring Boot permette di semplificare e velocizzare la configurazione e lo sviluppo di un’ap-plicazione Spring.

Spring Data fornisce un set di API, grazie alle librerie JPA e Hibernate, per gestire l’accesso ai dati indipendente dal tipo di DBMS utilizzato in modo facile ed immediato

(31)

4.1.2

MySQL

MySQL è un Database Management System (DBMS) di tipo relazionale. Si occupa di interagire con il database per persistere, gestire e recuperare i dati.

4.1.3

Thymeleaf

Thymeleaf è un template engine Java open-source per processare e creare file HTML, XML, JavaScript, CSS e di testo. Fornisce un’integrazione totale con Spring Framework e intende sostituire completamente le JavaServer Pages (JSP).

4.1.4

JUnit

Junit è un framework per effettuare test del codice per il linguaggio di programmazione Java. È stata utilizzata la versione 4 per testare tutte le parti del server.

4.1.5

Mockito

Mockito è un framework di testing open-source per Java che permette la creazioni di oggetti “mock” (chiamati anche test double1) in modo da verificare il comportamento del sistema da testare.

4.1.6

Node.js e Node Package Manager

"Node.js è una runtime di JavaScript Open source multipiattaforma orientato agli eventi per l’esecuzione di codice JavaScript Server-side, costruita sul motore JavaScript V8 di Google Chrome."2 Node.js include un package manager utilizzato per gestire le dipendenze di un progetto.

4.1.7

Webpack

Webpack è un module bundler per applicazioni JavaScript, ovvero consente di unire, ela-borare e convertire i moduli di un progetto generando un grafo delle dipendenze dei mo-duli necessari al progetto per funzionare. Sulla base di questo grafo crea uno, o più, file contenente l’indispensabile al progetto per funzionare. Permette di utilizzare un approccio modulare durante lo sviluppo.

1https://en.wikipedia.org/wiki/Test_double 2

https://it.wikipedia.org/wiki/Node.js

(32)

4.1.8

Sortable.js

Sortable.js è una libreria JavaScript open-source che, utilizzando le API native di HTML5, consente di rendere liste ordinabili tramite drag and drop.

4.1.9

Karma e Jasmine

Karma è un test runner che consente di creare un ambiente di testing. All’interno di questo ambiente si possono utilizzare vari framework di testing come Jasmine.

4.1.10

Fontawesome

Fontawesome è un toolkit open-source che fornisce un set di icone pronte e font per SCSS, HTML e JavaScript. Può venire importato ed utilizzato in un progetto grazie a NPM.

4.1.11

Coreui

Coreui è un template per creare dashboard di amministrazione basato su Bootstrap. È disponibile una versione gratuita ed un template di base pronto per l’uso. È facilmente inseribile in un progetto utilizzando NPM.

4.1.12

Echarts

Echarts è una libreria open-source per disegnare grafici. La libreria è rilasciata con licenza Apache 2.03. Attualmente Echarts fa parte del programma Incubator dell’Apache Software Foundation.

Si è deciso di utilizzare questa libreria perché offre delle performance superiori alla media, supporta un enorme quantità di tipologie di grafici e non utilizza librerie legacy. Inoltre offre la possibilità, in caso di bisogno, di aggiungere un’estensione per disegnare grafici utilizzando WebGL4.

4.2

Pianificazione del lavoro

Il lavoro, della durata di 8 settimane, è stato pianificato utilizzando la metodologia SCRUM con degli sprint bisettimanali.

3https://www.apache.org/licenses/LICENSE-2.0 4

(33)

In principo ci si è concentrati sulla gestione dei dati e sulla visualizzazione di un grafico per ogni canale. Durante questa fase si sono incontrati parecchi problemi nella gestione delle performance, soprattutto legati alla grande quantità di dati da caricare, analizzare e servire all’interfaccia grafica. Si è perciò dovuto dedicare parecchio tempo allo studio e all’implementazione di varie soluzioni che permettessero un caricamento, una lettura ed un’elaborazione dei dati maggiormente efficente. Si è cercato di bilanciare il carico di lavoro tra server e browser in modo da non sovraccaricare nessuna delle due componenti e di mantenere un’esperienza d’uso fluida e reattiva.

Una volta risolti i problemi di performance ci si è dedicati all’implementazione di un server che integrasse un database ed alla creazione di tutti gli elementi necessari, come le entità da persistere e gli endpoint da esporre, alla comunicazione tra interfaccia e backend. La tappa successiva è stata migliorare e aggiungere funzionalità all’interfaccia grafica in modo da ottenere un’esperienza d’uso che non si distaccasse troppo da Remlogic.

L’ultimo passo è stato separare definitivamente il codice che fa parte della libreria per l’an-notazione dei grafici dal resto del sistema e l’implementazione di un modo per aggiungere varie annotazioni ai diagrammi.

(34)
(35)

Capitolo 5

Risultati

(36)

5.1

Server

Il server è stato implementato utilizzando il framework Spring Boot e sfrutta MySQL per persistere le informazioni riguardanti i pazienti e le registrazioni. Inoltre fornisce svariati endpoint sfruttabili dall’interfaccia per richiedere e modificare informazioni sulle entità del DB e per ottenere i dati da visualizzare nei grafici.

5.1.1

Database

Grazie al framework Java Persistence API (JPA) si può facilmente associare il DBMS My-SQL al server.

Il database è composto da tre entità: Patient, Recording e Annotation.

Patient contiene tutte le informazioni riguardanti il paziente (Nome, Cognome, . . . ) ed un riferimento ad una lista delle sue registrazioni.

Una registrazione è rappresentata dall’entità Recording, la quale è composta da un id, due valori numerici che indicano il timestamp dell’inizio e della fine della registrazione (start, end), una lista di stringhe che rappresentano i sensori (channels) legati alla registrazione, una lista delle frequenze di campionamento (samplingsRate) per ogni sensore, una stringa che indica il nome del file contenente i dati (traces) e un’altra stringa che indica il nome del file contenente le annotazioni (annotations).

Un’Annotation rappresenta una nota aggiunta ad un grafico. Essa ha, oltre all’id, un campo che indica di quale evento si tratta, il timestamp dell’annotazione e la sua durata. Inoltre si salva anche un riferimento a quale registrazione è associata l’annotazione.

È stata creata una classe Traces che contiene: un array bidimensionale di float, che rap-presenta i valori delle registrazioni (data), una mappa, che associa ad ogni frequenza di campionamento un array di timestamps e due array di float, che contengono per ogni sen-sore il valore massimo e il valore minimo registrato (maxValues e minValues).

La registrazione di una sessione di sonno è formata normalmente da 8 ore di registrazione e quasi 50 sensori. Questo significa che per un canale che viene campionato a 200 Hz si hanno quasi 6 milioni di valori. Se ogni valore registrato viene salvato in un float si ottiene che un solo canale con campionamento a 200Hz occupa circa 23 MB di spazio. Per que-stioni di performance è quindi meglio salvare tutti i dati di una registrazione direttamente sul file system e mantenere nel DB solamente il riferimento al nome del file salvato. Per ogni registrazione si crea quindi un oggetto della classe serializzabile Traces che viene salvato come file binario direttamente sul file system e nel DB viene mantenuto solamente il riferi-mento al suo nome.

(37)

5.1.2

Struttura Classi

Il server è strutturato secondo la consueta configurazione di un progetto Spring. Nel packa-ge model sono presenti le entità Annotation, Patient e Recording che vengono persistite nel database, la classe Traces utilizzata per salvare nel file system i dati delle registrazioni e la classe Annotation utilizzata per costruire le annotazioni per i grafici.

Il collegamento tra il server ed il database avviene, grazie a Spring Data JPA, nelle classi PatientRepository e RecordingRepository del package repository. Queste classi vengono utilizzate dai rispettivi service per eseguire operazioni CRUD nel DB. Inoltre è presente un package storage le cui classi si occupano di gestire il salvataggio, il caricamento e la cancellazione dei file del file system del server.

5.1.2.1 EDFParser

Per leggere e convertire i file EDF si è sfruttato un parser scritto in Java distribuito con li-cenza MIT. Questo parser consente di leggere un file EDF, estrarre le informazioni salvate nell’header e i dati delle registrazioni. La grande quantità di dati da leggere ed elaborare causava però problemi legati all’occupazione della memoria. Si è quindi deciso di modifi-care leggermente le classi, rimuovendo i parametri ritenuti non necessari e modificando gli oggetti in cui si salvavano i dati. In particolare essi venivano salvati utilizzando la primitiva Java "double". In Java un double occupa uno spazio pari a 64-bit, si è deciso quindi di salvare tutti i dati utilizzando la primitiva "float" che occupa solamente 32-bit. Nonostante la diminuzione della precisione dei dati non sono state riscontrate delle differenze visive nella rappresentazione dei segnali, mentre i problemi di performance e di occupazione della me-moria sono drasticamente diminuiti. Questo parser è contenuto nel package EDFParser ed è formato da varie classi. Le informazioni sul paziente e la registrazione sono salvate nella classe EDFHeader, mentre i dati sono contenuti nella classe EDFSignal.

5.1.3

Downsampler

Il sottocampionamento dei dati avviene all’interno di una classe che estende l’interfaccia Do-wnsampler, che esponde un metodo getDownsampledPoint il quale, dati una lista di coor-dinate (coppie valore-timestamp) e una risoluzione desiderata ritorna la lista di coorcoor-dinate filtrata. Sono state implementati due tipi di Downsampler e si è confrontato il risultato di ognuno dei due con un grafico ottenuto utilizzando tutti i punti disponibili. La classe Median-Downsampler divide i dati ricevuti in N blocchi uguali, dove N è il valore più vicino possibile alla risoluzione desiderata che consente di avere blocchi uguali. Ad esempio se si ha una lista di 100 valori e si vuole una risoluzione di 23 dati non sarà possibile dividere i 100 valori in 23 blocchi di uguale dimensione. È quindi necessario trovare il primo valore maggiore di

(38)

23 che sia un divisore di 100, ovvero 25. Una volta divisi i dati in blocchi uguali si effettua la media di ogni blocco e si genera una lista finale di 25 elementi contenti le varie medie. Un altro tipo di sottocampionamento avviene nella classe NaiveDownsampler. Questa clas-se offre un sottocampionamento molto clas-semplice, ma con performance elevate. Data una lista di dati N ed una risoluzione M si calcola un valore X, detto step, pari al quoziente N/M. In seguito si scorre la lista di coordinate e si estrae un valore ogni X.

5.1.3.1 Confronto Downsampler

Per verificare quale Downsampler utilizzare si è confrontato il grafico generato da ognuno dei due metodi (naive o media) con un grafico generato tramite echarts al quale venivano passati tutti i dati.

Figura 5.1: Confronto tra Downsampler

Nella figura 5.1 è possibile osservare in alto un grafico generato senza sottocampiona-mento lato server, nel mezzo un grafico con il sottocampionasottocampiona-mento naive e in basso con un sottocampionamento effettuato usando la media. Nonostante sia evidente una perdita di precisione il grafico più somigliante all’originale è dato dal sottocampionamento naive, mentre utilizzando la media vi è uno "smussamento" dei dati che modifica eccessivamente l’andamento della linea.

Un risultato ancora migliore sarebbe ottenibile utilizzando altri metodi di sottocampionamen-to più sofisticati che garantiscano risultati visivamente ideali, come il mesottocampionamen-todo del Largest-Triangle.[4]

(39)

5.1.3.2 Controller

Il package controller è composto da cinque classi controller:

AnnotationController si occupa di mappare le richiesta GET e POST all’endpoint

"/annotations"

PagesController è una classe che si occupa di mappare la pagine index.html, ovvero

la pagina che corrisponde all’interfaccia del sistema, al percorso di base “/”. Nella pagina vengono iniettate alcuni oggetti che vengono gestiti tramite Thymeleaf.

PatientController si occupa di gestire le operazioni riguardanti i pazienti quali la

creazione, la modifica o l’eliminazione di un paziente. Queste operazioni avvengono tramite richieste GET, POST, PUT o DELETE all’endpoint "/patient".

ChartsController invece si occupa di gestire vari endpoint relativi ai grafici

RecordingsController è il controller che gestisce il caricamento del file edf e la

conversione dei dati

L’elaborazione dei dati delle registrazioni avviene all’interno del controller ChartsController, il quale offre i seguenti endpoint:

GET /start?filename=XXX

– REQUEST PARAM filename: nome del file da cui recuperare la registrazione – RETURN: ritorna il timestamp in millisecondi dell’inizio delle registrazioni

GET /end?filename=XXX

– REQUEST PARAM filename: nome del file da cui recuperare la registrazione – RETURN: ritorna il timestamp in millisecondi della fine delle registrazioni

GET /trace?filename=XXX&channel=000&start=000&end=00=&res=000 – REQUEST PARAM filename: nome del file da cui recuperare la registrazione – REQUEST PARAM channel: id del canale di cui si vogliono i dati

– REQUEST PARAM start: timestmap dell’inizio dei dati desiderati (opzionale) – REQUEST PARAM end : timestamp della fine dei dati (opzionale)

– REQUEST PARAM res: numero di punti da ritornare (opzionale)

– RETURN: ritorna il timestamp in millisecondi dell’inizio delle registrazioni

(opzio-nale)

(40)

– OSSERVAZIONI: Questo endpoint ritorna una lista di coppie valore-timestamp.

In questo endpoint è obbligatorio specificare il nome del file e il canale richiesto, mentre se gli altri parametri non verranno specificati si ritornerà l’intero segnale con una risoluzione default di 2000.

GET /channels?filename=XXX - ritorna la lista dei label dei canali di un determinato

file

– REQUEST PARAM filename: nome del file da cui recuperare la registrazione – RETURN: ritorna la lista dei label dei canali della registrazione

GET /load?filename=XXX

– REQUEST PARAM filename: nome del file da cui recuperare la registrazione – OSSERVAZIONI: questo endpoint serve per indicare al server di iniziare a

ca-ricare il file di registrazione e delle annotazioni in memoria. Grazie a questo endpoint è possibile precaricare i dati in memoria diminuendo il tempo di attesa di ricezione dei file nell’interfaccia. Il caricamento del file avviene all’interno di un metodo sincronizzato in modo da evitare qualsiasi problema di race condition nel caso in cui si abbiano più richieste in contemporanea.

Annotations Controller espone i seguenti endpoint:

GET /annotations?filename=XXX&start=000&scrollSize=000

– REQUEST PARAM filename: nome del file da cui recuperare la registrazione – REQUEST PARAM start: valore da cui iniziare a recuperare le annotazioni

(opzionale)

– REQUEST PARAM scrollSize: dimensioni delle finestre di tempo delle

annota-zioni

– RETURN: le annotazioni del file specificato come parametro

– OSSERVAZIONI: Vi sono due modi per effettuare una richiesta a questo

end-point:

∗ Specificando start e scrollSize il server ritornerà una lista di 3 array con-tentene le annotazioni "correnti", ovvero dal timestamp specificato in start per una durata pari al valore del parametro scrollSize, le annotazioni della finestra precedente e quelle della finestra successiva

∗ Specificando solamente il nome del file verrà ritornata un’unica lista conten-te tutti gli eventi del file delle annotazioni

(41)

– REQUEST PARAM duration: durata dell’evento, può valere 0 in caso di eventi

istantanei

– REQUEST PARAM event: stringa che indica di quale evento si tratta

– REQUEST PARAM timestamp: timestamp in millisecondi di inizio dell’evento – REQUEST PARAM recording: nome del file associato alla registrazione – RETURN: una risposta con bosy vuoto e stato OK

– OSSERVAZIONI: Questo metodo serve per salvare nel database

un’annotazio-ne inserita lato frontend

Il caricamento e il trattamento dei dati di una polisonnografia avviene all’interno della classe RecordingsController, che espone il seguente endpoint:

POST /recording?file=XXX&annotations=XXX&id=000. – REQUEST PARAM file: file EDF della polisonnografia

– REQUEST PARAM annotations: file .txt delle annotazioni esportato tramite

Rem-Logic

– REQUEST PARAM id : id del paziente a cui associare la registrazione

– OSSERVAZIONI: In questo metodo dapprima si recupera il paziente dal DB

tra-mite l’ID e gli si associa una nuova registrazione. In seguito si eseguono le seguenti operazioni:

∗ Lettura del file EDF con EDFParser

∗ Estrazione dei timestamp di inizio e fine, di una lista dei label dei canali e delle frequenze di campionamento con RecordingParser

∗ Salvataggio del file di annotazioni su disco

∗ Salvataggio delle tracce della registrazione su disco

∗ Persistenza della registrazione sul DB

Per ogni file da salvare su disco viene generato un nome che è composto dalle iniziali del nome, dalla data di registrazione, dall’id del paziente, una serie di 3 numeri identificativi del file e un suffisso che indica se è un file di dati o di annotazioni.

(42)

5.2

Libreria per grafici

Per implementare una libreria in cui si potesse visualizzare ed annotare i grafici ci si è basati su echarts. Si è tentato di creare un’astrazione sopra echarts.

5.2.1

Echarts

Per creare un grafico con echarts bisogna dapprima invocare il metodo echarts.init(container). Questo metodo crea l’istanza di un oggetto echartsInstance nel container passato come parametro. Il container può essere o un elemento div o un canvas. Nel caso in cui venga passato un div bisogna anticipatamente specificare le dimensioni del container, altrimenti echarts non riuscirà a creare l’istanza. L’istanza ritornata espone vari metodi, tra i quali il più importante è setOption(option, notMerge, lazyUpdate, silent)[5]. I parametri notMerge, lazyUpdate e silent sono opzionali.

L’oggetto option contiene i parametri e le informazioni necessarie per disegnare corretta-mente il grafico desiderato. Ogni campo di option identifica il componente di un’istanza di echarts.

5.2.1.1 Grid

L’oggetto grid è un campo dell’oggetto option ed è la sezione del canvas in cui sono disegnati i grafici. In un singolo grid possono esserci fino a 4 grafici Nella figura 5.2 si possono vedere

Figura 5.2: Esempio di un oggetto grid

alcuni dei possibili parametri da settare. Margin serve a settare il margine del grid all’interno del container, mentre height indica l’altezza del componente.

5.2.1.2 Series

Series è un array in cui si definisce, per ogni elemento di grid, il tipo di grafico da disegnare, quali componenti avrà e i dati da immettere.

(43)

Figura 5.3: Esempio di un oggetto series

Nella figura 5.3 si può vedere un esempio di un grafico a linea, in cui i dati vanno immessi nell’array data; non vengono visualizzati i singoli punti che compongono il grafico avendo showSymbol:false e la linea avrà dimensione 1. Il colore della linea viene passato dall’e-sterno assegnando color a itemStyle. In series è possibile specificare alcuni componenti grafici come markPoint, markLine o markArea, i quali vengono spiegati in seguito.

In series i dati vengono immessi come una lista di coppie che identificano le coordinate di ogni punto per l’asse X e l’asse Y.

5.2.1.3 xAxis

Nell’oggetto xAxis è possibile assegnare dei parametri per ogni asse X di grid.

Figura 5.4: Esempio di un oggetto xAxis

Nell’esempio della figura 5.4 si può vedere un asse X che ha come tipo il tempo. Viene ricevuto il valore in timestamp e, grazie alla funzione associata a formatter, viene convertito

(44)

in formato hh:mm:ss e mostrato sull’asse X. L’intero asse viene diviso in 10 parti, come specificato dal valore in splitNumber.

5.2.1.4 yAxis

L’oggetto yAxis è analogo ad xAxis ma per l’asse Y.

Figura 5.5: Esempio di un oggetto yAxis

La configurazione della figura 5.5 mostrerà un grafico con l’asse Y visibile, sarà diviso in un segmento solo come specificato in splitNumber, il nome sarà mostrato in verticale al centro del grafico ad una distanza di 30 pixel dall’asse.

5.2.1.5 Brush

Brush è un componente di echarts che serve a selezionare uno o più aree di dati di un grafico.

Figura 5.6: Esempio di un oggetto brush

Nel caso della figura 5.6 nell’oggetto option si specifica l’utilizzo di un brush su tutti gli assi X di grid. Toolbox serve a creare un icona in alto a destra del grafico per abilitare il brush, in seguito si specifica lo stile di brush e che deve venire invocato tramite debounce dopo 300 millisecondi dall’ultimo evento. Debounce è una funzione che consente di evitare che

(45)

un evento venga lanciato continuamente, ma solamente alla fine di un’azione o dopo un certo lasso di tempo. Ad esempio nel caso in cui si ridimensiona un finestra non si cerca di ridisegnare l’interfaccia in continuazione ma solamente ogni certo lasso di tempo. Questo serve a mantenere l’interfaccia reattiva. Utilizzando debounce con un valore di 300 si evita di lanciare continuamente l’evento brushSelected.

5.2.1.6 DataZoom

Il componente DataZoom viene utilizzato per zoomare l’area specifica di un diagramma. Vi sono 3 tipi di dataZoom: ’inside’, dove le funzionalità sono inserite all’interno del grafico, ’slider’ dove uno slider viene generato sotto al grafico per gestire lo zoom e ’select’ che permette di zoomare sull’area selezionata di un grafico. Il tipo inside permette di zoomare avanti e indietro utilizzando la rotella del mouse centrando lo zoom sulle coordinate del puntatore del mouse.

Figura 5.7: Esempio di un oggetto DataZoom

Nell’esempio in figura 5.7 è possibile vedere la configurazione di un componente datazoom sull’asse X, mentre l’asse Y non viene alterato. L’azione dataZoom viene invocata solamente ogni 80 millisecondi, mentre inizialmente tutti i dati sono visualizzati. I valori di start e di end indicano la percentuale di dati da visualizzare.

5.2.1.7 markLine

markLine è un componente interno a series. Viene utilizzato per disegnare delle righe su un grafico. Tra i vari parametri è possibile specificare la coordinata di partenza e di arrivo della linea e il tipo di linea (solid, dashed, ...). Un componente markLine può venire generato automaticamente da echarts per mostrare la media, il massimo o il minimo di un grafico.

(46)

Figura 5.8: Grafico con due componenti markLine

È possibile specificare dei simboli per l’inizio e per la fine della linea, come visibile nella figura 5.8 in cui si possono vedere due markLine orizzontali

5.2.1.8 markPoint

Markpoint è un componenente per marcare dei punti in un grafico. Si possono generare markPoint automatici per massimi e minimi, si possono modificare la forma che assume un markPoint, la sua dimensione e il testo inserito. Inoltre è possibile creare un markPoint in coordinate specifiche del grafico.

(47)

Nella figura 5.9 è possibile osservare 3 esempi di forme diverse di markPoint. In basso si ha un markpoint con forma ’pin’, sopra uno con forma rettangolare e uno a diamante.

5.2.1.9 markArea

markArea è un componente simile a markPoint e markLine. Consente di evidenziare ed aggiungere un label a una porzione di grafico. È possibile specificare, tra le altre cose, le coordinate di disegno e il colore della sezione evidenziata.

5.2.2

Astrazione di echarts

L’implementazione è basata su vari moduli che vengono utilizzati per disegnare un grafico e fornire diverse funzionalità, senza mai esporre elementi di echarts.

5.2.2.1 Pubsub

Il design pattern architetturale Publish-Subscribe è un pattern che consente di creare moduli che possano comunicare uno con l’altro minimizzando l’accoppiamento. Il modulo pubsub implementa 3 metodi che consentono di creare un sistema di Publish-Subscribe.

In una mappa subscribers vengono matenute in memoria quali callback vengono registrate. Vi è un metodosub(topic, subscriber) che viene invocato quando si vuole registrare una

callback. In questa funzione si salva nei subscribers la callback passata come secondo ar-gomento utilizzando come key topic.

Con il metodopub(topic, payload) si andrà ad eseguire la callback associata a topic

pas-sando payload come parametro. In questo modo è possibile eseguire funzioni di un modulo che ricevano paramametri inizializzati in moduli separati.

Con il metodo unsub è possibile rimuovere la registrazione di una funzione.

5.2.2.2 Dom

Il modulo Dom viene utilizzato per creare un’istanza di echarts. Mantiene in una variabile chart il riferimento ad un’istanza di echarts ed espone un metodo build(node, opts). In

questo metodo viene creata l’istanza di echarts all’interno dell’elemento node passato co-me paraco-metro. L’istanza viene poi ritornata alla funzione chiamante.

In seguito si invocachart.resize(opts). Il metodo resize serve a ridisegnare il grafico

corret-tamente all’interno dello spazio disponibile nel div, mentre nel parametro opts sono inserite le dimensioni massime che assumerà il grafico. Successivamente si istanzia un listener per l’evento ’resize’ in window in modo da richiamare il metodo resize() quando la finestra viene ridimensionata. Per alleggerire il carico di lavoro questa funzione viene invocata solo ogni

(48)

250 millisecondi grazie all’utilizzo del metodo throttle della libreria lodash[6]. Throttle è un metodo analogo a debounce spiegato in precedenza, ma invece di attendere la fine della generazione degli eventi invocato la funzione ogni tot di tempo.

5.2.2.3 OptionsBuilder

L’oggetto option da passare all’istanza di echarts viene creato e mantenuto all’interno del modulo OptionsBuilder. Questo modulo crea un oggetto options quando viene istanziato con i parametri di altezza, colore, margine e le opzioni per lo zoom (opzionali) che vengono passati dall’esterno come parametri iniziali di options. Questi parametri sono tutti obbligatori. Vengono esposti i seguenti metodi per ricevere e manipolare l’oggetto options creato:

• getOptions()e setOptions(chartOptions) - getter e setter per sostituire l’oggetto options creato

• getColor() e setColor(color) - getter e setter del parametro color

• getName() e setName(name) - getter e setter del nome dell’asse Y.

• setData(data) - modifica i dati inseriti nel grafico. Essi devono essere un’array di coppie di valori, ogni coppia avrà un timestamp per l’asse X e un valore numerico qualsiasi per l’asse Y

• appendData(data) - metodo che aggiunge dati a quelli già esistenti. Viene modificato l’array di dati il quale viene poi passato all’istanza di echarts, che determina automa-ticamente quali valori sono nuovi e aggiunge solamente i punti nuovi, senza dover ridisegnare tutto il grafico.

• setYaxisLimit(bound) - metodo che fissa i valori dell’asse Y. Il parametro è un array [min, max] i cui valori indicheranno il valore minimo e massimo dell’asse Y

• updateDataZoom(start, end) - metodo che aggiorna la percentuale di grafico visua-lizzata quando si effettua uno zoom. I parametri indicano la percentuale di dati da visualizzare. Ad esempio con updateDataZoom(25, 75) verrà visualizzato solamente il 50% dei dati presenti in mezzo al grafico

• addSquareAnnotation(markPoint, markLine) - metodo che aggiunge un markPoint e una markLine all’oggetto options. Gli oggetti servono a disegnare le note sul grafico. L’oggetto markPoint e markLine vengono creati nel modulo NotesBuilder

• addSelectionAnnotation(markPoint, markArea) - metodo che aggiunge un markPoint e una markArea al grafico, serve per disegnare le note con una durata superiore a 0 ms sul grafico.

(49)

5.2.2.4 NotesBuilder

Le note vengono create nel modulo NotesBuilder, il quale espone i seguenti metodi:

• getVerticalLine(xAxis, yMin, yMax, color=’#000’) - questo metodo crea un oggetto markLine, che nel grafico verrà visualizzato come una linea solida verticale che copre tutta l’altezza del grafico. xAxis è il valore dell’asse X dove disegnare la linea e deve essere un valore presente nei dati, altrimenti non verrà disegnata. Ad esempio se nella serie di dati si ha un timestamp 8 e quello seguente è 10 un eventuale linea con xAxis 9 non verrà rappresentata. yMin e yMax sono i valori dell’asse Y da cui la linea parte e termina. Color è un parametro opzionale, se non viene specificato la linea sarà disegnata in nero

• getMarkPoint(text, xAxis, yAxis, color = ’#000’) - l’oggetto ritornato da questa funzione è un oggetto markPoint. Viene utilizzato in seguito per disegnare un rettangolo sul grafico alle coordinate inserite con i valori xAxis e yAxis. La dimensione del rettangolo si adatta in base al testo da inserire

• getMarkArea(xLeft, xRight, color=’#000’) - ritorna un oggetto che serve per colorare una sezione del grafico, dal valore xLeft a quello xRight, del colore passato come parametro

5.2.2.5 EventNotificator

Un altro modulo legato alle annotazioni è EventNotificator, il quale espone un metodo re-gisterEvent. In questo metodo viene registrato in pubsub un metodo

dispatchCustomE-vent(params) con topic ’chartAnnotation’. DispatchCustomEvent lancia un evento persona-lizzato ’chartAnnotation’ con target document. L’evento serve per notificare all’esterno della libreria che un’annotazione è stata inserita e per recuperare le informazioni sull’annotazio-ne. All’interno dell’evento sono inserite alcune informazioni: channel (nome del grafico che è stato annotato), time, duration ed event (nome dell’evento annotato).

5.2.2.6 Chart

I moduli appena descritti vengono utilizzati all’interno del modulo principale della libreria: Chart, il quale espone i seguenti metodi:

init(node, canvasOpts, label, height, color, margin, dataZoomOptions) - questo

metodo deve venire chiamato per primo per istanziare un grafico.

Il parametro node deve essere un div o un canvas in cui verrà disegnato il grafico.

(50)

Il secondo parametro invece è un oggetto in cui devono venire specificati alcuni pa-rametri del grafico: canvasOpts è un oggetto che contiene la larghezza e l’altezza da assegnare inizialmente al container del grafico, label indica il nome da assegnare al grafico, height è l’altezza del grafico disegnato, margin i margini del grafico e dataZoo-mOptions è un oggetto che viene utilizzato per specificare come debba funzionare lo zoom sul grafico.

addSource(topic) - per poter comunicare i dati dall’esterno si utilizza il modulo

pub-sub. In questo metodo si effettua una registrazione con key del valore passato in topic. In seguito quando verrà invocato pub del topic in questione verrà lanciata la funzione drawChart(data). Questa funzione serve per disegnare il grafico con i dati ricevuti. L’oggetto data deve avere un campo min e uno max in cui sono salvati i valori minimi e massimo del grafico, un campo data in cui ci sarà una lista di coppie timestamp-valore del segnale e un campo label per inizializzare il nome dell’asse Y.

setColor(color - modifica il campo color di options e ridisegna la linea del grafico con

il colore appena passato

getColor() - ritorna il colore attuale del grafico

resize() - ridisegna il grafico adattandolo al container

on(eventName, callback, handler) - metodo che serve per associare gli eventi di

echarts a delle funzioni personalizzate. Ad esempio si può eseguire la una determi-nata funzione quando il grafico lancia l’evento ’dataZoom’.

setData(data) - serve per aggiornare solamente il campo data del grafico,

mantenen-do gli altri parametri invariati

appendData() - metodo per aggiungere dati ad un grafico. Viene registrato un topic in

pubsub con subscriber la funzione addData(data). Questa funzione aggiunge ai dati già presenti quelli ricevuti come parametro e ridisegna il grafico aggiungendo i dati precedentemente mancanti. Al termine dell’esecuzione di addData la funzione viene invocato unsub.

showLoadingAnimation() - questo metodo mostra uno spinner mentre si attende

che il grafico venga disegnato.

updateDataZoom(start, end) - modifica il livello di zoom del grafico, mostrando i dati

che vanno da start ad end

getName() - ritorna il nome del grafico

getDataZoomValues() - metodo che ritorna un array contenente i valori di zoom del

(51)

enableNote(text, color) - questo metodo serve per attivare le note su di un

grafi-co, modificando un flag noteDisabled e per specificare di quale colore devono venire disegnate e con quale testo

disableNote() - rimette il flag noteDisabled a true impedendo agli altri metodi di

disegnare le note

callFunctionOnClick(callback) - questo metodo esegue la funzione passata come

parametro ogni qualvolta che un click sul grafico viene eseguito. Quando viene rilevato un click sul grafico la funzione recupera, tramite la funzione di echarts convertFrom-Pixel, le coordinate del grafico che sono state premute. In seguito richiama callback passando come parametro la coppia di coordinate.

addAnnotationToOption(text, timestamp, duration, color) - questo metodo crea

un oggetto markPoint e un oggetto markLine con i parametri ricevuti utilizzando il modulo NotesBuilder. In seguito aggiunge gli elementi creati ad options del grafico, senza però ridisegnare il grafico.

redrawChart() - questo metodo ridisegna il grafico utilizzando l’oggetto options. Un

utilizzo può essere di ridisegnare il grafico dopo aver aggiunto diverse note con il metodo descritto sopra. In questo modo l’operazione di ridisegno del grafico viene effettuata una sola volta, alleggerendo il carico di lavoro del browser.

activateInstantNotes() - metodo analogo a callFunctionOnClick. Rileva un click sul

grafico e trasforma la coordinata X del click nel valore più vicino presente nei dati, crea un oggetto markLine e uno markPoint usando il valore estratto e il testo e il colore definiti con enableNote. In seguito disegna la nota su sul grafico e invoca pubsub.pub con topic ’chartAnnotation’ e payload le informazioni sull’annotazione. Pub eseguirà la funzione registrata nel metodo dispatchCustomEvent nel modulo EventNotificator.

activateSelectionNotes() - metodo analogo al precedente, ma invece di essere in

ascolto dell’evento click sfrutta il metodo on(’brushselected’) di echarts per aggiunge una nota quando un’area del grafico viene selezionata con brush.

(52)

5.3

Interfaccia Grafica

L’interfaccia grafica è stata implementata utilizzando CoreUI[7], un template gratuito per creare dashboard di amministrazione basato su Bootstrap 4, mentre la parte dinamica è stata realizzata utilizzando JavaScript.

È composta da un’unica pagina web in cui vengono eseguite tutte le operazioni.

Figura 5.10: Pagina web iniziale

La figura 5.10 rappresenta come si presenta la pagina inzialmente.

L’interfaccia è composta da una barra superiore, due menu laterali e un corpo centrale. Nel-la barra superiore sono presenti 3 bottoni (Recording, Annotations Hotkey e Patients), i quali attivano le rispettive finestre nel menu laterale sinistro.

Nella figura 5.10 è attivata la finestra "Recording", nella quale si possono effettuare le se-guenti operazioni sulle registrazioni: caricarne una, gestire quelle correnti, caricare i dati di una.

La finestra "Annotations Hotkey" mostrà una lista di possibili note da aggiungere ai grafici con, a fianco di ognuna, la lettera da premere sulla tastiera per attivarla.

La finestra "Patients" consente invece di aggiungere nuovi pazienti e visualizzare le infor-mazioni o modificare ed eliminare quelli già inseriti.

Per caricare una nuova registrazione bisogna effettuare un click sul bottone "Upload New Recording". Questo bottone consente l’apertura di una finestra di dialogo in cui è possibile

(53)

scegliere il paziente a cui abbinare la registrazione e caricare il file edf e il file txt delle annotazioni sul server.

Figura 5.11: Finestra di dialogo per l’upload di una nuova registrazione

Nella figura 5.11 si possono vedere il form per caricare una registrazione. Una volta pre-muto il bottone la progress bar si anima mostrando la percentuale di caricamento del file. Al termine del caricamento i dati vengono inviati al server all’endpoint "/recording" con un metodo POST. In seguito si aspetta che il server termini di analizzare ed estrarre i dati dal file edf. Una volta caricato e convertito correttamente il file edf la pagina viene ricaricata, e la polisonnografia appena inserita verrà mostrata nella lista sottostante i due bottoni. Il bottone Manage Recording apre un’altra finestra di dialogo nella quale è possibile visua-lizzare una lista di registrazioni, delle relative informazioni e eseguire delle operazioni. Allo stato attuale è possibile visualizzare solamente il nome del paziente abbinato e, premendo il bottone rosso con l’icona di un cestino, eliminare dal server la relativa registrazione. La finestra è stata strutturata in questo modo cosicché se durante eventuali sviluppi futuri vi fos-sero delle altre informazioni da aggiungere ad una registrazione, come ad esempio il nome dell’operatore addetto ad effettuare lo scoring, il componente sarebbe facilmente adattabile.

(54)

Figura 5.12: Finestra di gestione delle registrazioni

Nel menù laterale sinistro, sotto i due bottoni per gestire e caricare i dati, viene creata dinamicamente una lista di registrazioni divise in base ai pazienti a cui sono associate. Da questo elenco è possibile scegliere quale polisonnografia si intende visualizzare. Premendo una registrazione si aprirà una finestra in cui sarà possibile scegliere quali canali visualizzare in forma grafica e la dimensione della finestra temporale.

Figura 5.13: Finestra di dialogo per caricare i canali

Nella figura 5.13 è possibile vedere la finestra di dialogo che si apre quando si clicca su una registrazione nel menù laterale sinistro. Quando si preme il bottone di conferma verranno caricati i dati nel server e nel corpo centrale verranno mostrati i grafici selezionati. All’interno del primo grafico verranno disegnate le note già presenti, le quali possono venire visualizza-te nel menù lavisualizza-terale destro, nel quale è possibile scegliere se vedere una lista di tutvisualizza-te le novisualizza-te

(55)

esistenti o solamente quelle della finestra corrente, della finestra temporale precedente e di quella successiva. Sopra i grafici scelti verrà disegnato un ipnogramma attraverso il quale è possibile spostarsi all’interno dei grafici. Effettuando un click su di esso infatti verrà caricata la finestra in cui è presente il timestamp premuto.

Figura 5.14: Grafici disegnati con note1

Nella figura 5.14 è possibile vedere una serie di grafici. Il primo grafico rosso indica l’ipno-gramma, mentre nel secondo è possibile vedere 3 note caricate dal server. Il menù laterale destro indica la presenza di 4 note nella finestra attualmente visualizzata, mentre in quella precedente e in quella successiva non ce ne sono. La quarta nota è stata aggiunta nel terzo grafico ed ha una durata di 12.07ms. Dopo essere stata aggiunta il menù laterale viene ag-giornato. Premendo il bottone "All" nel menù destro è possibile visualizzare la lista di tutte le annotazioni.

(56)

Figura 5.15: Dettaglio di un grafico con menù contestuale

Come si può vedere nella figura 5.15 effettuando un click destro su un grafico viene aperto un menu contestuale nel quale è possibile modificare il colore del grafico o aggiungere altri 30 secondi di dati. Di default ogni grafico viene disegnato in colore nero. Nella figura 5.17 è possibile vedere 2 grafici con colori personalizzati.

La gestione dei pazienti avviene nel menù laterale sinsitro nella finestra "Patients".

Figura 5.16: Sezione della finestra Patients

Nella figura 5.16 è possibile vedere la finestra Patients. Vi è un bottone per aggiungere un nuovo paziente, che una volta premuto aprirà una form in cui sarà possibile inserire nome, cognome, altezza, peso, data di nascità, sesso ed eventuali osservazioni sul paziente.

(57)

Figura 5.17: Form per la creazione di un paziente

Premendo su un bottone contenente il nome di un paziente verrà invece aperto lo stesso form ma con i campi inizializzati. In questo modo sarà possibile visualizzare le informazioni sul paziente, modificarle oppure eliminarlo.

Figura 5.18: Form per la modifica del paziente

(58)

5.3.1

JavaScript

Tutta la parte dinamica della pagina web è stata implementata utilizzando JavaScript. Il codice è formato da vari moduli separati, mentre le variabili utilizzate da più moduli sono salvate in un oggetto esportato dal modulo Settings. Al fine di mantenere l’implementazione più generica possibile si è evitato di utilizzare librerie per i data binding.

5.3.1.1 Settings

Questo modulo esporta un oggetto che contiene tutte le variabili utilizzate in più moduli dell’applicazione.

Figura 5.19: Modulo Settings

Nell’oggetto Setttings sono contenuti tutti dati necessari per costruire i grafici: le dimensioni del canvas, il colore della linea, i margini da tenere o come effettuare lo zoom sul grafico. Altri dati salvati riguardano il timestamp di inizio e di fine della finestra di dati attualmente visualizzata, una dimensione di quanto scorrere i dati in avanti o indietro e quali sono il

Riferimenti

Documenti correlati

Tecniche per ottenere per via geometrica dal grafico di una funzione, il grafico di altre funzioni5. da

• Fare click con il tasto destro in una zona bianca vicino al bordo esterno del grafico Dal menu che compare scegliere la fase che si vuole modificare: Tipo di grafico, Dati

Risolvere graficamente la disequazione data equivale a determinare la ascisse dei punti della semicirconferenza che hanno ordinata minore di quella dei corrispondenti punti di

Se proiettiamo i rami della funzione sull’asse delle ascisse e oscuriamo le zone del piano ove il grafico della funzione non compare, potremo osservare

Disequazioni – metodo

behaviour of stakeholders; that information be not false, unaccounted for, or incomplete, such as to induce stakeholders to take decisions that clash with or harm their own

Dai dati emersi nelle diverse quattro analisi per i diversi quattro ruoli chiave, è corretto poter affermare che empiricamente vi è una sostanziale differenza di attitudine

Then the second sub-chapter is looking toward the factors that affected the survival rate of tree seedlings, principally related to planting date & climate, location of the