Archivi tag: Processing

Alcuni lavori dei miei studenti del corso CMTI dell’università di Udine #2

Il primo articolo con la spiegazione e un po’ di background in merito al corso e ai lavori di data visualization dei miei studenti lo trovate qui.

In questo post pubblico, con il loro permesso, le infografiche realizzate dagli studenti che hanno sostenuto l’esame al secondo appello.

Passione film con i dati di IMDB

Il primo lavoro è di Omar Frasson, appassionato di cinema, che grazie ai dati raccolti su IMDB ha sviluppato una visualizzazione piuttosto articolata.

Omar Frasson, data visualization IMDB

La prima schermata, che funge da splash screen, è già, di per sé, una visualizzazione: i nomi dei registi dei film appaiono, infatti, a grandezza differente in base al numero di lungometraggi visti. La posizione sullo schermo, invece, è casuale.

Data visualization IMDB film

Nella prima schermata, tutti i film vengono ordinati sull’asse delle x per anno di uscita. Sull’asse delle y, invece, la durata del film e, attraverso il colore, è possibile vedere il voto assegnato.

Passando con il mouse sopra a ciascun rettangolo compaiono alcuni dati sul film.

Visualizzazione di dati IMDB infografica

La visualizzazione per generi con animazione controllata dallo slider in alto con riferimento sempre l’anno di uscita del film. Sulla destra, invece, alcuni eventi rilevanti della storia del cinema.

Omar Frasson, data visualization registi

Terza schermata: visualizzazione per registi con comparazione tra la votazione assegnata dallo studente e quella media generale di tutti gli utenti di IMDB.

Omar Frasson data visualization IMDB

Schermata che rappresenta dei dati relativamente alla durata dei film e alle valutazioni assegnate.

E, infine, una comparazione tra tutti i film visti da Omar nel 2017 e nel 2018.

Tutto sugli Avengers

Rimaniamo in ambito cinematografico con il lavoro di Giulia Nardò che ha deciso di creare una data visualization sulla serie degli Avengers. I dati sono stati raccolti da varie fonti (Wikipedia, IMDB, ecc…) e assemblati in un file excel.

Giulia Nardo data visualization Avengers

Una prima schermata mostra l’universo degli Avengers con tutti i personaggi (cerchio esterno) e film (cerchi interni). Muovendosi con il mouse è possibile vedere quali personaggi erano presenti nei film. La legenda sulla sinistra aiuta molto a capire le varie relazioni e la scelta dei colori.

Giulia Nardo Avengers Iron Man
Dettaglio sul personaggio Iron Man
Ronan the accuser data visualization avengers
Dettaglio sul personaggio Ronan the accuser

Cliccando sui personaggi o sul film è possibile avere ulteriori dettagli

Giulia Nardo Avenger Endgame data visualization
Dettaglio su: Avengers: Endgame.

Visualizzare i dati raccolti con l’App Salute su iOS

Il progetto di Erika Corallo, invece, si è concentrato sulla visualizzazione dei dati raccolti con l’App Salute su iOS: battito cardiaco, distanze percorse e passi.

L’approccio è stato piuttosto semplice nel disegnare i grafici ma la parte, a mio modo di vedere, più interessante, sono le schermate iniziali che sono animate e già rappresentano i dati in modo molto creativo.

Erika Corallo, visualizzazione dati salute iOS
Erika Corallo, data visualization salute
Erika Corallo my steps visualizzazione infografica

Per ciascun dato esiste, poi una vista dettagliata suddivisa per mese oppure generale per anno.

Clash of Clans

Williams Piazza ha utilizzato i dati presi dall’API del gioco Clash of Clans per valutare il rendimento di ciascun giocatore del suo clan per capire come migliorare le prestazioni di gioco.

Alcuni lavori dei miei studenti del corso CMTI dell’Università di Udine

Due anni fa ho iniziato a lavorare come docente a contratto per il corso di Laurea Magistrale in Comunicazione Multimediale e Tecnologie dell’Informazione (CMTI) dell’Università degli Studi di Udine.

La materia che insegno si chiama Linguaggi Visuali per Sistemi Complessi e, all’interno del percorso, offre un punto di contatto tra l’anima informatica (Virtual Reality, Machine Learning, Cybersecurity ecc…) e tra il mondo del design (Design dello Spazio, Interaction Design, ecc…).

In questo post ho deciso di condividere – con il loro permesso – alcuni dei lavori presentati al primo appello d’esame da alcuni studenti e studentesse del corso.

La scelta del tema era libera e ciascuno/a ha sviluppato in completa autonomia sia il lavoro di ricerca che di visualizzazione.

Premessa: il background e i contenuti del corso

Il background di chi frequenta il corso è molto vario ma, in generale, chi ha competenze in ambito informatico non ha mai lavorato prima con la grafica e viceversa.

Nel percorso didattico che ho sviluppato e che sto perfezionando di anno in anno, cerco di portare tutti ad acquisire delle competenze in entrambi questi ambiti attraverso lo studio della programmazione in Processing e con analisi ed esercitazioni in classe di data visualisation.

L’occupazione dei neo-laureati

Partendo dai dati di Almalaurea, Michelangelo ha deciso di fare una visualizzazione interattiva e animata sulle percentuali di neo-laureati che trovano lavoro dopo un anno dal conseguimento del titolo.

Un grafico che mostra le statistiche occupazionali dei neo laureati dopo un anno dal conseguimento del titolo. Corso CMTI Università di Udine
Data Visualisation di Michelangelo Campanella, fonte dati: Almalaurea

I colori di un film

Kristian si è concentrato sull’analisi dei colori dei suoi film preferiti (Apocalypse Now, Blade Runner, Mad Max, ecc…). Nel realizzare questo progetto ha incontrato due difficoltà:

  • estrarre i dati analizzando i film frame per frame
  • creare una visualizzazione unica che permettesse l’interpretazione dei dati raccolti.
Corso CMTI Università di Udine. Visualizzazione di Kristian Simonato.
Un’analisi approfondita sull’utilizzo del colore nel cinema di Kristian Simonato

Anche in questo caso, trattandosi di una visualizzazione interattiva, lo screenshot che ho condiviso non rende giustizia al lavoro svolto. Partendo da questo studio sull’utilizzo dei colori nel cinema, il primo grafico (in alto) mostra quanto ciascun frame tende a uno dei sette colori principali analizzati nello studio.

Nella parte centrale è possibile vedere il colore predominante in ciascun frame, vedere il frame di riferimento nel film un’analisi più approfondita con le percentuali di ciascun colore.

Il grafico 3D sulla sinistra, che si può ruotate, presenta un’analisi completa e numerica delle componenti colore dell’intero film.

Mappare le nascite del Friuli Venezia Giulia

Data Visualization delle nascite nel Friuli Venezia Giulia suddivise per comune. Corso CMTI Università di Udine
Una mappa interattiva per mappare le nascite nel Friuli Venezia Giulia di Michele Dal Zotto, fonte dati: ISTAT

Prendendo i dati dell’ISTAT, Michele ha visualizzato su una mappa interattiva le nascite dal 2013 al 2017 nella sua regione, il Friuli Venezia Giulia.

È possibile interagire con la mappa cliccando sui comuni per vedere il dettaglio oppure selezionando il dato generale o quello di maschi/femmine.

Featuring tra rapper e artisti italiani

Sfruttando i dati presi dall’API di Spotify, Niccolò è andato ad analizzare alcuni dei suoi musicisti/cantanti preferiti e le loro collaborazioni.

Ne nasce un grafico interattivo dove ciascun artista è rappresentato da un cerchio, il cui colore varia in base al genere musicale di riferimento (scelto in modo arbitrario). I featuring tra gli artisti sono rappresentati dalle linee di collegamento: più è spessa la linea, maggiori sono le collaborazioni tra i due artisti.

Data Visualization Niccolò Bellucco - Corso CMTI Università di Udine
Data Visualization Niccolò Bellucco - Corso CMTI Università di Udine

Cliccando su un artista (immagine sopra) si può entrare nel dettaglio mentre, cliccando sui nodi (immagine sotto) che rappresentano le collaborazioni è possibile visualizzare dei dati aggiuntivi sui brani.

Nella versione animata, le barre verdi si muovono come fossero animate dall’audio del brano.

Data Visualization Niccolò Bellucco - Corso CMTI Università di Udine con API di Spotify

La diffusione delle microplastiche nell’acqua

Il lavoro di Tania e Silvia si può vedere on-line. Hanno deciso di concentrare la loro attenzione su un tema molto attuale: la diffusione delle microplastiche nelle acque.

Microplastic: il lavoro di Tania Scorpio e Silvia Gioia Florio. In questa immagine un mock-up di una locandina per un’esibizione.

Cliccando sul menu a destra è possibile visualizzare informazioni diverse sulla mappa. La cosa interessante è che i dati raccolti provengono dal database di Adventure Scientists, un gruppo volontari che raccolgono dati in giro per il mondo per aiutare gli scienziati.

Fonte dati: Adventure Scientists

L’area dell’Oceano Atlantico che salta subito all’occhio non è più inquinata delle altre, semplicemente in quella fascia sono stati raccolti moltissimi campioni durante una competizione nautica.

Interessante anche il grafico forecast che vuole azzardare una previsione di quanto saranno inquinati gli oceani da qui al 2050 se non dovessimo cambiare immediatamente il nostro modo di produrre microplastiche.

Analisi di una relazione su Telegram

Sicuramente ispirato dal progetto che ho mostrato in classe Call me Adele, Francesco ha deciso di analizzare i dati generati dalla chat di Telegram con la sua fidanzata (più di 80 mila messaggi).

I risultati sono molto interessanti e credo che le immagini parlino da sole; anche in questo caso l’applicazione originale è interattiva e permette di navigare facilmente tra le varie schermate e di scendere nel dettaglio quando necessario.

Grafico a barre II

Nell’articolo precedente abbiamo cominciato a lavorare al nostro primo grafico a barre utilizzando come fonte i dati presenti all’interno di un file CSV.

In questo articolo andremo a completare la visualizzazione inserendo anche le temperature massime e dei riferimenti.

Array delle temperature massime

I dati relativi alle temperature massime sono già presenti dentro al file CSV. Come abbiamo già visto, per comodità inseriamo questi dati in un array.

Dove abbiamo dichiarato le variabili, aggiungiamo:

float tempMin[], tempMax[];

Inizializziamo l’array:

tempMax = new float[0];

Inseriamo i dati utilizzando lo stesso ciclo for per non appesantire troppo il programma

for (int i = 1; i < csv.getColumnCount(); i++) {
  tempMin = append(tempMin, csv.getFloat(0, i));
  tempMax = append(tempMax, csv.getFloat(3, i));
}

Grafico a barre delle temperature massime

Utilizzando sempre il codice che abbiamo già scritto, aggiungiamo nel ciclo for in cui andavamo a disegnare i rettangoli delle temperature minime, quelli relativi alle massime. Per differenziarle a livello visivo utilizzeremo il colore rosso.

fill(255, 100, 100);
rect(x, height - 50, 36, tempMax[i] * - 20);

Siccome i rettangoli rossi saranno più alti rispetto a quelli azzurri, assicuriamoci di disegnarli per primi.

Nel mio codice ho aggiunto anche un noStroke() per eliminare il bordo.

Grafico a barre con temperature massime

Aggiungiamo dei riferimenti

Quando si creano delle visualizzazioni di dati può essere utile dare dei riferimenti a chi sta osservando il nostro lavoro per aiutarli nella comprensione. L’immagine qui sopra presa singolarmente potrebbe rappresentare migliaia di cose differenti.

Aggiungere delle linee di riferimento è questione di un semplice ciclo for:

for (int j = 0; j <= 20; j++) {
  stroke(0, 30);
  line(30, height - 50 + (j * - 20), 470, height - 50 + (j * - 20));
}

Grafico a barre con riferimenti in Processing

Ora non ci resta che aggiungere il testo (aggiungiamo un paio di linee di codice al precedente ciclo for):

textAlign(RIGHT, CENTER);
for (int j = 0; j <= 20; j++) {
  fill(0, 127);
  text(j + "°", 25, height - 52 + (j * - 20));
  stroke(0, 30);
  line(30, height - 50 + (j * - 20), 470, height - 50 + (j * - 20));
}

Grafico a barre in Processing

Per rendere il grafico più leggibile facciamo dei piccoli miglioramenti: scriviamo il valore numerico ogni cinque gradi e schiariamo leggermente le altre linee:

textAlign(RIGHT, CENTER);

for (int j = 0; j <= 20; j++) {
  if (j % 5 == 0) {
    fill(0, 127);
    text(j + "°", 25, height - 52 + (j * - 20));
    stroke(0, 30);
  } else {
    stroke(0, 15);
  }
  line(30, height - 50 + (j * - 20), 470, height - 50 + (j * - 20));
}

Realizzare un grafico a barre in Processing

Non ci resta che aggiungere l'anno di riferimento in fondo al grafico: avendo aggiunto l'opzione header nella lettura del file CSV viene saltata completamente la prima riga che include proprio questo dato. Potremmo riscrivere il codice ma, per questa volta, adotteremo una soluzione più semplice anche se non proprio elegante. Per completezza includo tutto il codice del programma:

/*
 * Grafico a barre, 2
 * Federico Pepe, 29.04.2018
 * http://blog.federicopepe.com/processing
 */

Table csv;

float tempMin[], tempMax[];

void setup() {
  size(500, 500);
  background(255);
  noStroke();
  csv = loadTable("data.csv", "header");

  println("Numero righe: " + csv.getRowCount());
  println("Numero colonne: " + csv.getColumnCount());

  tempMin = new float[0];
  tempMax = new float[0];

  for (int i = 1; i < csv.getColumnCount(); i++) {
    tempMin = append(tempMin, csv.getFloat(0, i));
    tempMax = append(tempMax, csv.getFloat(3, i));
  }

  printArray(tempMin);

  println("Il valore minimo è: " + min(tempMin));
  println("Il valore massimo è: " + max(tempMin));

  noLoop();

  int x = 50;
  int year = 2008;

  for (int i = 0; i < tempMin.length; i++) {
    fill(255, 100, 100);
    rect(x, height - 50, 36, tempMax[i] * - 20);
    fill(100, 190, 255);
    rect(x, height - 50, 36, tempMin[i] * - 20);
    fill(0, 127);
    text(year, x + 2, height - 30);
    x += 40;
    year++;
  }

  textAlign(RIGHT, CENTER);

  for (int j = 0; j <= 20; j++) {
    if (j % 5 == 0) {
      fill(0, 127);
      text(j + "°", 25, height - 52 + (j * - 20));
      stroke(0, 30);
    } else {
      stroke(0, 15);
    }
    line(30, height - 50 + (j * - 20), 470, height - 50 + (j * - 20));
  }
}

void draw() {
}

Bar Graph in Processing

Coding Rescue #3 – Cambiare la tonalità di alcuni pixel

Negli ultimi giorni ho ricevuto diverse richieste di aiuto per problemi di codice in Processing; ecco la soluzione a uno dei problemi che mi sono stati posti.

Ho deciso di chiamare questo Coding Rescuecambiare la tonalità di alcuni pixel.

Il problema

Il quesito era piuttosto articolato:

  • Il programma deve caricare un’immagine dal disco.
  • Il programma decide se modificare o no il pixel in base ad un valore casuale.
  • Il processo di trasformazione viene controllato dal click  del mouse: un primo click avvia la trasformazione che, con un successivo click, viene messa in pausa. Un ulteriore click fa ripartire la trasformazione e così via.
  • I pixel devono essere modificati di continuo.
  • Il compito deve essere svolto mediante la funzione creaImmagine(), che accetta in ingresso un oggetto di tipo PImage e rende in uscita un oggetto di tipo PImage, che sarà l’immagine modificata come da specifiche, e la funzione calcolaPixel(), che accetta in ingresso un oggetto di tipo color e rende in uscita un oggetto di tipo color, che sarà il pixel modificato come da specifiche.
  • creaImmagine() crea una nuova immagine utilizzando su ciascun pixel la funzione calcolaPixel().
  • calcolaPixel() calcola il nuovo pixel nel seguente modo: siano r, g, b i livelli di canale di un pixel. Sia treshold un valore numerico posto inizialmente a 0.5. Sia r un valore casuale compreso tra 0 e 1, generato per ogni pixel. Se r>soglia, allora la funzione lascia il pixel inalterato, in caso contrario il programma calcola i nuovi valori rm, gm, bm (che definiscono il pixel
    modificato) nel seguente modo:

    • rm = 0.393∗r+0.769∗g+0.189∗b
    • gm = 0.349∗r+0.686∗g+0.168∗b
    • bm = 0.272∗r+0.534∗g+0.131∗b

    In ogni caso i valori finali di r, g, b devono essere valori leciti, cioè compresi tra 0 e 255.

  • Quando l’utente preme il tasto “+” la soglia viene incrementata di 0.1 mentre, con la pressione del tasto “-” la soglia viene decrementata di 0.1.

La soluzione


/*
 * Coding Rescue #3 - Cambiare la tonalità di alcuni pixel
 * Federico Pepe, 21.01.2018
 * http://blog.federicopepe.com/processing
 */

// Creo le variabili necessarie;
float threshold = 0.5;
boolean work = true;
PImage original, edited;

void setup() {
  // Nella funzione di setup carico il file dall'hard disk;
  size(1, 1);
  surface.setResizable(true);
  selectInput("Select a file to process:", "fileSelected");
}

void draw() {
  if (original != null) {
    edited = original.copy();
    /*
     * Se la variabile work, il cui valore dipende dal click del mouse è true, mostro
     * l'immagine originale, altrimenti avvio la modifica
     */
    if (work) {
      image(edited, 0, 0);
    } else {
      image(creaImmagine(edited), 0, 0);
    }
  }
}

// Funzione per gestire il caricamento dei file da HD
// https://processing.org/reference/selectInput_.html
void fileSelected(File selection) {
  if (selection == null) {
    println("Window was closed or the user hit cancel.");
  } else {
    println("User selected " + selection.getAbsolutePath());
    original = loadImage(selection.getAbsolutePath());
    surface.setSize(original.width, original.height);
  }
}

// Funzione creaImmagine che, come da specifiche, accetta in ingresso un oggetto PImage
// e restituisce un oggetto PImage;
PImage creaImmagine(PImage img) {
  // Carico i pixel in un array
  img.loadPixels();
  for (int y = 0; y < img.height; y++) {
    for (int x = 0; x < img.width; x++) {
      int loc = x + y * img.width;
      // Ottengo i valori R, G, B di ciascun pixel;
      float r = red(img.pixels[loc]);
      float g = green(img.pixels[loc]);
      float b = blue(img.pixels[loc]);
      // Lancio la funziona calcolaPixel
      img.pixels[loc] = calcolaPixel(color(r, g, b));
    }
  }
  img.updatePixels();
  return img;
}

color calcolaPixel(color c) {
  // Valore casuale, come da specifiche
  float r = random(0, 1);

  if (r > threshold) {
    // Se r è maggiore della soglia, restituisco il colore originale
    return c;
  } else {
    // Altrimenti calcolo il nuovo valore del pixel come richiesto
    // la funzione constrain mi assicura che il valore calcolato sia compreso tra 0 e 255;
    float rm = constrain(0.393*red(c)+0.769*green(c)+0.189*blue(c), 0, 255);
    float gm = constrain(0.349*red(c)+0.686*green(c)+0.168*blue(c), 0, 255);
    float bm = constrain(0.272*red(c)+0.534*green(c)+0.131*blue(c), 0, 255);
    // Restituisco i nuovi valori
    return color(rm, gm, bm);
  }
}

// Con la funzione keyPressed determino la pressione dei tasti + e -
void keyPressed() {
  if (key == '+') {
    threshold += 0.1;
  }
  if (key == '-') {
    threshold -= 0.1;
  }
  // Utilizzo la funzione round (di seguito) per arrotondare il valore a 2 decimali;
  round(threshold, 2);
}
// Alla pressione del mouse, cambio il valore di work da true a false e viceversa
void mouseClicked() {
  work = !work;
}
// Funzione utile per limitare il numero di decimali in un float
// https://stackoverflow.com/questions/9627182/how-do-i-limit-decimal-precision-in-processing
float round(float number, float decimal) {
  return (float)(round((number*pow(10, decimal))))/pow(10, decimal);
} 

Quick, Draw! + Processing: lavorare con il dataset di Google con più di 50 milioni di disegni

Quick, Draw! in Processing

A fine 2016 Google ha messo on-line Quick, Draw! uno dei suoi esperimenti di intelligenza artificiale e machine learning. Il sito chiede alle persone di disegnare delle forme: un maiale, un tubo per annaffiare il prato, una padella, ecc… e in meno di 20 secondi, attraverso una rete neurale, il computer prova a indovinare cosa è stato disegnato.

Più di 15 milioni di persone hanno partecipato al gioco e, così facendo, Google è riuscita a raccogliere un dataset di più di 50 milioni di disegni che, qualche giorno fa, è stato rilasciato pubblicamente.

Il dataset si compone di 345 categorie e, oltre ai dati vettoriali delle immagini sono inclusi anche una serie di metadati.

L’obiettivo del rilascio di questi dati è:

We’re sharing them here for developers, researchers, and artists to explore, study, and learn from.

Nel giro di poche ore sul mio feed twitter sono comparsi i primi esperimenti (i più interessanti sono quelli di @frauzufall che trovate qui) la maggior parte dei quali, però, generati con OpenFrameworks.

Non trovando nessuno che stesse utilizzando Processing, ho deciso di scrivere un piccolo programma in questo linguaggio per dare la possibilità a tutti di utilizzare questo dataset

Struttura dei dati

I file che si scaricano dal repository rilasciato da Google sono file di tipo .ndjson ovvero file con un oggetto di tipo JSON per ogni riga di file.

Ciascun oggetto è composto dai seguenti dati:

  • key_id (integer): numero univoco che identifica il disegno
  • word (string): la categoria che era stata richiesta
  • recognized (boolean): se il disegno era stato riconosciuto (true) oppure no (false)
  • timestamp (datetime): quando il disegno è stato creato
  • countrycode (string): due lettere per identificare la nazione del giocatore
  • drawing (string): un array JSON contenente i dati vettoriali del disegno
{ 
    "key_id":"5891796615823360",
    "word":"nose",
    "countrycode":"AE",
    "timestamp":"2017-03-01 20:41:36.70725 UTC",
    "recognized":true,
    "drawing":[[[129,128,129,129,130,130,131,132,132,133,133,133,133,...]]]
  }

Per semplificarmi la vita, mi sono concentrato solo sull’ultimo tipo di dato: il mio obiettivo era caricare i dati del dataset e ridisegnare le forme con Processing.

L’array contenente i dati del disegno è a sua volta strutturato in questo modo:

[ 
  [  // First stroke 
    [x0, x1, x2, x3, ...],
    [y0, y1, y2, y3, ...],
    [t0, t1, t2, t3, ...]
  ],
  [  // Second stroke
    [x0, x1, x2, x3, ...],
    [y0, y1, y2, y3, ...],
    [t0, t1, t2, t3, ...]
  ],
  ... // Additional strokes
]

Per fortuna la documentazione di Google è molto chiara: x e y sono le coordinate e t è il tempo trascorso in millisecondi dal primo punto.

Dati preprocessati

I dati contenuti nel dataset sono molti e, infatti, ciascun file pesa diverse centinaia di megabyte. Per fortuna il team di Google ha messo a disposizione anche dei file preprocessati: sono state rimosse le informazioni temporali e tutti i dati sono stati allineati e ridimensionali in un quadrato di 256×256 pixel.

I file .ndjson prepocessati sono disponibili a questo link e, come potete notare, la dimensione è notevolmente ridotta anche se si tratta, pur sempre, di almeno 40-50 megabyte per file.

Importare i dati in Processing

Primo problema: in Processing non esistono funzioni che ci permettono di lavorare su oggetti di tipo JSON differenti a meno che non siano inclusi in un array. All’inizio avevo, dunque, optato per modificare il file dei dati ma, grazie al suggerimento di un utente su Facebook, ho scoperto l’esistenza dell’oggetto BufferedReader che si usa per leggere un file una riga alla volta.

Una volta risolto questo inghippo, tutto è diventato più semplice: le linee restituite dall’oggetto sono di tipo String. Con la funzione parseJSONObject() ho convertito la stringa in un oggetto JSON.

Quick, Draw!

Quick, Draw: il dataset di Google in Processing
Vorrei conoscere chi ha disegnato questa “incudine”

Avendo accesso all’oggetto JSON, l’unico passaggio da fare era estrarre dall’array drawing i dati x e y e assegnarli ai vertici di una forma per poterla disegnare a schermo.

Per farli ho usato un’insieme di funzioni di cui parleremo in futuro.

Per i più curiosi, il codice è disponibile su questo repository su GitHub.