Dati Rustici Visualizzazione dei dati con Plotters – Parte 1

Dati Rustici con Plotters - Parte 1

Una guida dettagliata su come trasformare numeri grezzi in grafici stupendi in Rust

Diverse funzionalità di Plotters (Immagine dell'autore)

TLDR;

Plotters è una popolare libreria Rust per la creazione di visualizzazioni dei dati. Fornisce una vasta gamma di strumenti e funzioni per aiutarti a creare grafici, istogrammi e altre visualizzazioni di alta qualità. Questo articolo è la parte 1 di una serie di articoli che si concentra sugli aspetti estetici delle visualizzazioni preparate con Plotters. Dalla modifica dello schema di colori all’aggiunta di annotazioni, imparerai come personalizzare gli aspetti estetici delle visualizzazioni di Plotters.

Alla fine di questo articolo, avrai una comprensione solida di come utilizzare la libreria Plotters per creare visualizzazioni professionali che cattureranno l’attenzione del tuo pubblico. La libreria Ndarray sarà anche utile durante questo articolo mentre esploriamo l’uso di vari strumenti e metodi per la manipolazione dei dati. Quindi, che tu sia un amatore o un programmatore Rust esperto, la lettura di questo articolo è fondamentale se ti interessa creare visualizzazioni informativo ma anche esteticamente piacevoli con Plotters.

Nota: Questo articolo presume che tu abbia una conoscenza abbastanza di base del linguaggio di programmazione Rust.

Il notebook chiamato 6-plotters-tutorial-part-1.ipynb è stato sviluppato per questo articolo ed è disponibile nel seguente repository:

GitHub – wiseaidev/rust-data-analysis: Il corso di analisi dei dati definitivo con Rust.

Il corso di analisi dei dati definitivo con Rust. Contribuisci allo sviluppo di wiseaidev/rust-data-analysis creando un…

github.com

Indice

∘ TLDR; ∘ Indice ∘ Per chi è scritto questo articolo? ∘ Cosa è Plotters? ∘ Vantaggi di Plotters ∘ Configurazione di Plotters ∘ Grafici a linea singola ∘ Grafici multilinea ∘ Griglia, assi e etichette ∘ Colori e marcatori ∘ Sottografici ∘ Barre di errore ∘ Scatter plot ∘ Isto + gramma ∘ Conclusioni ∘ Nota di chiusura ∘ Risorse

Per chi è scritto questo articolo?

Foto di Myriam Jessier su Unsplash

Per coloro interessati a creare visualizzazioni intuitive dei dati in Rust, questo articolo è un must-read. Che tu sia un data scientist esperto o alle prime armi, la crate Plotters in Rust può aiutarti a creare grafiche coinvolgenti e accattivanti che sicuramente impressioneranno il tuo pubblico. Con una conoscenza di base della programmazione Rust, iniziare non è mai stato così facile.

La crate Plotters offre un potenziale immenso quando si tratta di creare visualizzazioni stupende ed efficaci in modo rapido e semplice, perfetto per progetti personali e professionali. È uno strumento che ti consentirà di generare grafiche di alta qualità in grado di comunicare in modo efficace informazioni complesse.

Se migliorare ulteriormente le tue capacità di visualizzazione ti sembra interessante, allora non cercare oltre questo pezzo! Le spiegazioni chiare unite a grafici utili rendono semplice seguire le istruzioni passo dopo passo, garantendo un rapido progresso nella produzione di visualizzazioni mozzafiato utilizzando la libreria Plotters.

Cos’è Plotters?

Foto di Stephen Phillips - Hostreviews.co.uk su Unsplash

Plotters è una robusta e flessibile libreria Rust che consente agli sviluppatori, come te, di creare visualizzazioni sorprendenti con facilità. La sua versatilità consente la creazione di vari tipi di grafici, tra cui linee, scatter e istogrammi, offrendo allo stesso tempo un’elevata flessibilità nelle opzioni di stile e annotazioni personalizzate.

Questo strumento all-in-one consente agli sviluppatori di definire qualsiasi tipo di visualizzazione necessaria, rendendolo un asset indispensabile per le attività di analisi dei dati. Una caratteristica degna di nota è il supporto per interfacce interattive che rende possibile la generazione di grafici statici e la creazione di applicazioni web senza sforzo. Questa capacità facilita l’esplorazione dei dati portando a diversi tipi di grafici adatti per progetti di machine learning o data science.

Inoltre, Plotters si integra perfettamente in popolari ambienti di sviluppo come Jupyter Notebook, supportando al contempo pacchetti avanzati dedicati esclusivamente al miglioramento dell’esperienza di visualizzazione dei dati, offrendo ulteriori motivi per includere questa libreria nell’arsenale di ogni sviluppatore!

Se sei appena all’inizio del tuo percorso o stai già analizzando complessi set di dati, Plotters offre un’adattabilità senza pari unita a una facilità d’uso; meritando davvero il riconoscimento tra gli strumenti di primo livello disponibili oggi!

Vantaggi di Plotters

Foto di UX Indonesia su Unsplash

La visualizzazione dei dati è un aspetto cruciale dell’analisi dei dati e la libreria Plotters fornisce diversi vantaggi per semplificare il processo. Un vantaggio significativo che lo distingue dalle altre opzioni è la sua natura user-friendly. L’integrazione con comuni librerie di analisi dei dati come Ndarray rende facile l’uso insieme a strutture familiari.

Un altro vantaggio degno di nota nell’utilizzo di questo strumento open source risiede nella sua convenienza economica; sviluppatori e analisti possono utilizzare la libreria senza alcun costo o limitazione sui diritti di utilizzo. Inoltre, chiunque sia interessato a contribuire al miglioramento del software può farlo come parte di un’effort comunitario.

Inoltre, essendo open source significa un rapido supporto online da parte di altri membri in tutto il mondo tramite varie piattaforme come forum come stackoverflow – rendendo l’elaborazione dei problemi efficiente!

Configurazione di Plotters

Per utilizzare appieno le capacità di Plotters, è fondamentale assicurarsi di aver configurato correttamente l’ambiente. La libreria offre una vasta gamma di tipi di grafico come grafici a linee, scatter plot, istogrammi e grafici a torta; tuttavia, senza una corretta configurazione, queste funzionalità rimangono inaccessibili. Fortunatamente per tutti noi, la configurazione di Plotters è un processo semplice: esegui semplicemente un comando nel tuo Jupyter Notebook e sei pronto!

:dep plotters = { version = "^0.3.5", default_features = false, features = ["evcxr", "all_series", "all_elements"] }

Una volta importato nel tuo spazio di lavoro del progetto o nella sessione del notebook, Plotters ti consente di esplorare la sua vasta gamma di opzioni di personalizzazione adattate specificamente alle tue esigenze, che tu abbia bisogno di grafici semplici o complessi.

Grafici a Linea Singola

Un grafico a linea singola lineare (Immagine dell'autore)

I grafici a linee sono uno strumento di visualizzazione fondamentale nella libreria Plotters che ci consente di rappresentare punti dati collegati da linee rette. In questa sezione, esploreremo il concetto di grafici a linea singola, che coinvolgono l’utilizzo della struttura LineSeries per creare visualizzazioni con una sola linea.

La struttura LineSeries in Plotters è ampiamente utilizzata per la visualizzazione dei dati, soprattutto nella creazione di grafici a linea singola. Tali grafici sono perfetti per illustrare le correlazioni tra due variabili o evidenziare i modelli all’interno dei dati di serie temporali.

Per creare un grafico unidimensionale attraverso Plotters, inizia importando la libreria e utilizzando la sua funzione draw_series insieme alla struttura LineSeries per disegnare il tuo grafico a linea con un dataset assegnato. Ad esempio, se vogliamo illustrare le cifre di vendita per mese tramite un grafico semplice, ecco come puoi utilizzare la funzione draw_series:

evcxr_figure((640, 240), |root| {    let mut chart = ChartBuilder::on(&root)        .build_cartesian_2d(0f32..5f32, 0f32..5f32)?;    let x_axis = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0];    chart.draw_series(LineSeries::new(        x_axis.map(|x| (x, x)),        &RED,    ))?;    Ok(())}).style("width:100%")

Nel codice sopra abbiamo un array x che rappresenta entrambe le coordinate, x e y. Proseguiamo poi esaminando un diverso caso in cui utilizziamo un array Ndarray per rappresentare i dati del grafico a linea singola:

evcxr_figure((640, 240), |root| {    let mut chart = ChartBuilder::on(&root)        .build_cartesian_2d(0f32..7f32, 0f32..7f32)?;        let x_axis = Array::range(1., 7., 1.);        chart.draw_series(LineSeries::new(        x_axis.into_raw_vec().into_iter().map(|x| (x, x)),        &RED,    ))?;    Ok(())}).style("width:100%")

Procediamo poi visualizzando un grafico quadratico rappresentato dall’equazione y = f(x) = x³. Ecco il codice corrispondente:

let points_coordinates: Vec<(f32, f32)> = {    let x_axis = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];    let quadratic: Vec<f32> = x_axis.iter().map(|x| i32::pow(*x as i32, 3) as f32).collect::<Vec<f32>>();    x_axis.into_iter().zip(quadratic).collect()};points_coordinates// Output// [(1.0, 1.0), (2.0, 8.0), (3.0, 27.0), (4.0, 64.0), (5.0, 125.0), (6.0, 216.0)]

Ora, dobbiamo tracciare questo vettore come segue:

evcxr_figure((640, 240), |root| {    let mut chart = ChartBuilder::on(&root)        .build_cartesian_2d(0f32..7f32, 0f32..220f32)?;    chart.draw_series(LineSeries::new(        points_coordinates.iter().map(|(x, y)| (*x, *y)),        &RED,    ))?;    Ok(())}).style("width:100%")
Un grafico di funzione cubica (Immagine dell'autore)

In sintesi, i grafici a linea in Plotters offrono un approccio efficace per illustrare correlazioni e tendenze all’interno dei dataset. Possiamo creare rappresentazioni informative ma coinvolgenti delle nostre informazioni utilizzando la struttura LineSeries manipolando gli array/vettori di valori x e valori y. Che tu stia esplorando risultati di ricerca scientifica o analizzando metriche aziendali, questi grafici a linea sono strumenti indispensabili per esplorare ulteriormente il tuo dataset e comunicare efficacemente le sue intuizioni con gli altri.

Grafici multilinea

Un grafico multilinea (Immagine dell'autore)

Plotters fornisce una eccezionale capacità di visualizzare più grafici in un singolo output, che ci permette di presentare numerose curve contemporaneamente nella stessa visualizzazione. Questo attributo notevole facilita il confronto e l’analisi dei set di dati. Per approfondire questa nozione, esaminiamo un esempio illustrativo:

evcxr_figure((640, 240), |root| {    let mut chart = ChartBuilder::on(&root)        .build_cartesian_2d(0f32..7f32, 0f32..220f32)?;    chart.draw_series(LineSeries::new(        linear_coordinates.iter().map(|(x, y)| (*x, *y)),        &RED,    ))?;    chart.draw_series(LineSeries::new(        quadratic_coordinates.iter().map(|(x, y)| (*x, *y)),        &GREEN,    ))?;    chart.draw_series(LineSeries::new(        cubic_coordinates.iter().map(|(x, y)| (*x, *y)),        &BLUE,    ))?;    Ok(())}).style("width:100%")

Utilizzando il frammento di codice fornito, possiamo generare numerose curve con facilità. Questo viene ottenuto invocando la funzione draw_series più volte e definendo i valori x da un array accoppiati con i corrispondenti valori y derivati da diverse espressioni matematiche. Dopo l’esecuzione di questo codice, verrà visualizzato un grafico completo che mostra tutte queste curve tracciate a scopo di osservazione.

Approfondiamo un altro esempio che dimostra l’adattabilità dei grafici multilinea. Osserva il seguente frammento di codice:

let points_coordinates: Vec<(f32, f32)> = {    let x_y_axes = array!([[1., 2., 3., 4.], [1., 2., 3., 4.]]);    let x_axis: Vec<f32> = x_y_axes.slice(s![0, 0, ..]).to_vec();    let y_axis: Vec<f32> = x_y_axes.slice(s![0, 1, ..]).to_vec();    x_axis.into_iter().zip(y_axis).collect()};// [(1.0, 1.0), (2.0, 2.0), (3.0, 3.0), (4.0, 4.0)]evcxr_figure((640, 240), |root| {    let mut chart = ChartBuilder::on(&root)        .build_cartesian_2d(0f32..5f32, 0f32..5f32)?;    chart.draw_series(LineSeries::new(        points_coordinates.iter().map(|(x, y)| (*x, *y)),        &RED,    ))?;    Ok(())}).style("width:100%")

Il frammento di codice in questione coinvolge un array Ndarray x con due dimensioni, che contiene set di dati distinti. Ogni riga rappresenta valori unici. Quando la funzione draw_series viene chiamata sull’intero array, Plotters lo interpreta come curve multiple da tracciare contemporaneamente. Il risultato mostra entrambi i set di dati affiancati per facilitare il confronto e l’analisi dei loro schemi, tendenze o altre caratteristiche degne di nota in modo intuitivo, consentendoci di trarre conclusioni significative da essi visivamente senza molto sforzo.

Per dimostrare l’adattabilità dei grafici multilinea, possiamo creare una rappresentazione visuale utilizzando dati arbitrari. Osserva questo frammento di codice come illustrazione:

let random_samples: Vec<(f32, f32)> = {    let x_y_axes = Array::random((2, 5), Uniform::new(0., 1.));    let x_axis: Vec<f32> = x_y_axes.slice(s![0, ..]).to_vec();    let y_axis: Vec<f32> = x_y_axes.slice(s![0, ..]).to_vec();    x_axis.into_iter().zip(y_axis).collect()};random_samplesevcxr_figure((640, 240), |root| {    let mut chart = ChartBuilder::on(&root)        .build_cartesian_2d(0f32..1f32, 0f32..1f32)?;    chart.draw_series(LineSeries::new(        random_samples.iter().map(|(x, y)| (*x, *y)),        &RED,    ))?;    Ok(())}).style("width:100%")

In questo frammento di codice, abbiamo utilizzato la funzione Ndarray Array::random per creare una matrice bidimensionale di dati popolata con valori arbitrari. Ogni volta che si utilizza questo metodo, genera un insieme esclusivo di punti dati. Stampando la matrice risultante, è possibile esaminare da vicino questi numeri casuali. La chiamata draw_series mostra entrambe le righe del nostro dataset come curve individuali su un singolo grafico. Poiché ogni esecuzione produce output casuali diversi, ogni grafico generato sarà unico e introdurrà un po’ di imprevedibilità e diversità nella tua esperienza di visualizzazione.

Per riassumere, la capacità di visualizzare più grafici in un’unica uscita con Plotters è una caratteristica potente per l’esplorazione e l’analisi dei dati. Che si tratti di tracciare curve distinte, confrontare dataset o sfruttare dati casuali, i grafici multilinea offrono una visione completa delle informazioni disponibili. Utilizzando la funzionalità di Plotters e sperimentando con diverse fonti di dati, è possibile creare visualizzazioni di impatto che facilitano una migliore comprensione e la presa di decisioni.

Griglia, Assi e Etichette

Plotters Grid (Immagine dell'autore)

Nel mondo della visualizzazione dei dati, è fondamentale avere la flessibilità di presentare una griglia in un grafico. La libreria Plotters ci permette di realizzare questo abilitando la funzione di griglia. Incorporando semplicemente l’istruzione chart.configure_mesh().draw()?; nel nostro codice, possiamo migliorare l’aspetto visivo e la chiarezza dei nostri grafici.

evcxr_figure((640, 240), |root| {    let mut chart = ChartBuilder::on(&root)        .build_cartesian_2d(0f32..1f32, 0f32..1f32)?;    chart.configure_mesh().draw()?;    Ok(())}).style("width:100%")

La riga ChartBuilder::on(&root).build_cartesian_2d(0f32..1f32, 0f32..1f32)?; ci consente di impostare manualmente i limiti dell’asse x da 0 a 1 e dell’asse y da 0 a 1. Specificando questi intervalli, abbiamo un controllo preciso sulla regione visualizzata del nostro grafico, garantendo che i punti dati più rilevanti siano evidenziati.

Per migliorare la chiarezza e la comprensione dei nostri grafici, è essenziale fornire etichette appropriate per gli assi e un titolo descrittivo. Consideriamo il seguente frammento di codice come esempio:

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Demo Grafico", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(0f32..1f32, 0f32..1f32)?;        chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 0.1);")        .y_desc("y = f(x)")        .draw()?;        Ok(())}).style("width: 60%")
Plotters labels (Immagine dell'autore)

In questo codice, abbiamo aggiunto l’istruzione chart.configure_mesh().x_desc(“x = Array::range(1., 7., 1.);”).y_desc(“y = f(x)”).draw()?; per arricchire il nostro grafico con annotazioni significative. Includendo x_desc(“x = Array::range(1., 7., 1.);”), etichettiamo l’asse x con una breve descrizione dei dati rappresentati. Allo stesso modo, y_desc(“y = f(x)”) assegna un’etichetta all’asse y, indicando la relazione funzionale. Inoltre, Caption(“Demo Grafico”, (“Arial”, 20).into_font()) fornisce un titolo informativo per dare contesto al grafico. Questi elementi migliorano collettivamente l’interpretabilità della visualizzazione, garantendo che gli spettatori possano comprendere facilmente lo scopo e il contenuto dei grafici.

Oltre alle etichette e ai titoli, Plotters ci permette di creare una legenda per distinguere tra più curve all’interno di un grafico. Passando un argomento per il parametro label nella funzione label e successivamente chiamando la funzione legend, possiamo generare una legenda. Considera il seguente esempio di codice:

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Demo del Plot", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(1f32..7f32, 1f32..14f32)?;        let x = Array::range(1., 7., 0.1);        chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 1.);")        .y_desc("y = f(x)")        .draw()?;    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, *x)),        &RED    )).unwrap()        .label("y = x")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &RED));        chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, *x * 2.0)),        &GREEN    )).unwrap()        .label("y = 2 * x")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &GREEN));    chart.configure_series_labels()        .background_style(&WHITE)        .border_style(&BLACK)        .draw()?;    Ok(())}).style("width: 60%")
Un grafico multilinea con etichette, legenda e griglia (Immagine dell'autore)

Eseguendo questo codice, creiamo una legenda che corrisponde alle varie curve nel nostro grafico. La funzione legend() genera automaticamente una legenda basata sulle etichette fornite dopo aver chiamato la funzione draw_series(). Aiuta gli spettatori a identificare e differenziare tra le diverse funzioni che vengono tracciate. In combinazione con la griglia, le etichette degli assi e il titolo, la legenda migliora la leggibilità complessiva e la comprensione del grafico.

Per impostazione predefinita, la casella della legenda è posizionata nella parte centrale destra del grafico. Tuttavia, se preferiamo cambiare la posizione della casella della legenda, possiamo farlo specificando un parametro di posizione SeriesLabelPosition nella funzione position. Modifichiamo di conseguenza il nostro snippet di codice:

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Demo del Plot", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(1f32..7f32, 1f32..14f32)?;        let x = Array::range(1., 7., 0.1);        chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 0.1);")        .y_desc("y = f(x)")        .draw()?;    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, *x)),        &RED    )).unwrap()        .label("y = x")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &RED));        chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, *x * 2.0)),        &GREEN    )).unwrap()        .label("y = 2 * x")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &GREEN));    chart.configure_series_labels()        .position(SeriesLabelPosition::UpperMiddle)        .background_style(&WHITE)        .border_style(&BLACK)        .draw()?;    Ok(())}).style("width: 60%")
Un grafico multilinea con una legenda posizionata in alto al centro del grafico (Immagine dell'autore)

Includendo il parametro position(SeriesLabelPosition::UpperMiddle) sulla funzione configure_series_labels, riposizioniamo la casella della legenda in alto al centro del grafico. Ciò ci consente di regolare con precisione la posizione della legenda, garantendo che non interferisca con le curve tracciate o altre annotazioni. La possibilità di personalizzare la posizione della legenda contribuisce alla versatilità ed estetica del nostro grafico.

Comprendendo ed utilizzando queste funzionalità in Plotters, possiamo creare grafici visivamente accattivanti ed informativi, personalizzare i limiti degli assi, aggiungere etichette e titoli, incorporare legende e salvare le nostre visualizzazioni come file immagine. Queste capacità ci permettono di comunicare ed presentare efficacemente i nostri dati in modo convincente e significativo.

Colori e Marcatori

Plotters offre una vasta gamma di stili e marcatori per progettare grafici visivamente accattivanti e comprensibili. Gli stili ti consentono di modificare l’aspetto delle linee, mentre i marcatori aiutano ad enfatizzare particolari punti dati sul tuo grafico. Combinando colori, stili e marcatori diversi con le funzionalità di Plotters, puoi creare grafici distintivi su misura per le tue esigenze.

Plotters offre mappe di colore avanzate che consentono la visualizzazione di dati complessi con una varietà di colori. Con il parametro style di Plotters, puoi selezionare una gamma di mappe di colore predefinite o creare la tua personalizzata utilizzando una struttura incorporata come RGBColor. Questo parametro si rivela particolarmente utile quando si rappresentano dati che comprendono ampi intervalli di valori o si enfatizzano specifiche linee di tracciamento o qualsiasi altra forma. Puoi fare riferimento alla palette completa per diversi valori di colore RGB.

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Demo Grafico", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(1f32..7f32, 1f32..14f32)?;        let x = Array::range(1., 7., 0.1);        chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 0.1);")        .y_desc("y = f(x)")        .draw()?;    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, *x)),        &RGBColor(0,0,255) // rosso: 0, verde: 0, blu: 255 -> il colore è blu     ))?;        Ok(())}).style("width: 60%")
Un grafico a linea singola con colore blu (immagine dell'autore)

In questo esempio, abbiamo cambiato il colore della linea in blu. Puoi anche utilizzare altri formati di colore, come HSLColor, per specificare colori personalizzati utilizzando i valori dello spettro HSL.

Per valorizzare l’aspetto visivo dei tuoi grafici a linea in Plotters, considera l’incorporazione di marcatori per rappresentare simboli distinti per ogni grafico. Se desideri un tocco personalizzato, ci sono diversi modi per personalizzare questi marcatori. In primo luogo, possiamo utilizzare il metodo draw_series tracciando i tuoi dati due volte con uno stile di marcatori come dimensione e colore basato su preferenze personali o caratteristiche specifiche del set di dati.

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Demo Grafico", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(1f32..7f32, 1f32..8f32)?;        let x = Array::range(1., 7., 0.1);        chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 0.1);")        .y_desc("y = f(x)")        .draw()?;    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, *x)),        &RED    ))?;    chart.draw_series(x.map(|x| {        EmptyElement::at((*x, *x))        + Cross::new((0, 0), 2, GREEN) // coordinate relative a EmptyElement    }))?;    Ok(())}).style("width: 60%")
Un grafico lineare con una singola linea e marcatori (immagine dell'autore)

In alternativa, possiamo impostare la dimensione del marcatore utilizzando il metodo point_size, che consente di creare un marcatore a cerchio pieno o aperto.

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Demo del grafico", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(1f32..7f32, 1f32..8f32)?;        let x = Array::range(1., 7., 0.1);        chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 0.1);")        .y_desc("y = f(x)")        .draw()?;    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, *x)),        &RED    ).point_size(2))?; // marcatore a cerchio aperto    Ok(())}).style("width: 60%")
Un grafico a linea con marcatori (immagine dell'autore)

Puoi combinare tutte queste tecniche (ad esempio colori, marcatori, legenda) per personalizzare la visualizzazione come segue:

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Demo del grafico", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(1f32..7f32, 1f32..342f32)?;        let x = Array::range(1., 7., 0.1);        chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 0.1);")        .y_desc("y = f(x)")        .draw()?;    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, *x)),        RED.filled()    ).point_size(2)).unwrap()        .label("y = x")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &RED));    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, (*x).powi(3))),        BLUE    ).point_size(2)).unwrap()        .label("y = x ^ 3")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &BLUE));    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, (*x).powi(2))),        &GREEN    )).unwrap()        .label("y = x ^ 2")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &GREEN));    chart.draw_series(x.map(|x| {        EmptyElement::at((*x, (*x).powi(2)))        + Cross::new((0, 0), 2, WHITE) // coordinate relative a EmptyElement    }))?;    chart.configure_series_labels()        .background_style(&WHITE)        .border_style(&BLACK)        .draw()?;    Ok(())}).style("width: 60%")
Un grafico multilinea con diverse linee colorate, marcatori, etichette, titolo e legenda (immagine dell'autore)

Nel complesso, Plotters offre un modo semplice e senza sforzo per personalizzare colori e marcatori, consentendoti di creare visualizzazioni eccezionali. Selezionando le apposite tavolozze di colori, i tuoi grafici possono comunicare in modo efficace informazioni preziose con facilità. La scelta del colore e del marcatore giusti può fare la differenza nel trasmettere con successo il tuo messaggio.

Sottografici

Plotters sottografici (immagine dell'autore)

La tecnica dei sottografici è un modo potente per visualizzare più grafici nello stesso output. Questo metodo si rivela particolarmente utile quando si desidera confrontare diversi set di dati o mostrare vari aspetti di un singolo set di dati. Con Plotters, la creazione di sottografici diventa un’attività semplice in quanto consente di creare una griglia in cui la posizione di ogni grafico successivo può essere specificata in relazione al suo predecessore.

Inoltre, ogni sottografico ha specifiche personalizzabili come titoli ed etichette che rendono facile per gli utenti personalizzare i loro output secondo le esigenze specifiche. I sottografici sono particolarmente utili nel trattare informazioni complesse in contesti scientifici e di analisi dei dati, poiché aiutano a comunicare in modo conciso ma efficace importanti scoperte.

Per generare sottografici in Plotters, puoi utilizzare il metodo split_evenly che richiede un parametro: una tupla composta da conteggio righe e conteggio colonne. Ad esempio, se desideri creare una disposizione 1×2 per i tuoi sottografici mentre rappresenti i dati nel primo, utilizza questo frammento di codice:

let linear_coordinates: Vec<(f32, f32)> = {    let x_y_axes = array!([[1., 2., 3., 4.], [1., 2., 3., 4.]]);    let x_axis: Vec<f32> = x_y_axes.slice(s![0, 0, ..]).to_vec();    let y_axis: Vec<f32> = x_y_axes.slice(s![0, 1, ..]).to_vec();    x_axis.into_iter().zip(y_axis).collect()};let quadratic_coordinates: Vec<(f32, f32)> = {    let x_y_axes = array!([[1., 2., 3., 4.], [1., 4., 9., 16.]]);    let x_axis: Vec<f32> = x_y_axes.slice(s![0, 0, ..]).to_vec();    let y_axis: Vec<f32> = x_y_axes.slice(s![0, 1, ..]).to_vec();    x_axis.into_iter().zip(y_axis).collect()};evcxr_figure((640, 480), |root| {    let sub_areas = root.split_evenly((1,2)); // griglia 1x2 (1 riga, 2 colonne)    let graphs = vec![        ("y = x", linear_coordinates.clone(), &RED),        ("y= x ^ 2", quadratic_coordinates.clone(), &GREEN),    ];    for ((idx, area), graph) in (1..).zip(sub_areas.iter()).zip(graphs.iter()) {        let mut chart = ChartBuilder::on(&area)            .caption(graph.0, ("Arial", 15).into_font())            .x_label_area_size(40)            .y_label_area_size(40)            .build_cartesian_2d(0f32..5f32, 0f32..17f32)?;        chart.draw_series(LineSeries::new(            graph.1.iter().map(|(x, y)| (*x, *y)),            graph.2,        )).unwrap()            .label(graph.0)            .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &GREEN));        chart.configure_mesh()            .y_labels(10)            .light_line_style(&TRANSPARENT)            .disable_x_mesh()            .x_desc("x = Array::range(1., 7., 0.1);")            .y_desc(graph.0)            .draw()?;    }    Ok(())}).style("width:100%")

In questo modo verrà creata una griglia 1×2 di sottografici e verranno rappresentati i dati in entrambi i sottografici, con titolo ed etichette degli assi specificati. L’argomento tuple passato a split_evenly rappresenta la griglia (1 riga e 2 colonne). Ci sono molti modi per fare i sottografici in Plotters, utilizzando split_vertically, split_horizontally, split_evenly e split_by_breakpoints.

Utilizzando le capacità di Plotters per la suddivisione dei grafici, diventa possibile ottenere visualizzazioni sorprendenti che aiutano la comunicazione presentando in modo chiaro ed accurato le informazioni.

Barre di errore

Un singolo grafico con barre di errore verticali (immagine dell'autore)

Per rappresentare accuratamente i dati, è fondamentale riconoscere e rendere trasparente la possibilità di errore. Questo può essere raggiunto attraverso l’uso delle barre di errore – rappresentazioni grafiche che mostrano la variabilità delle misurazioni e indicano i livelli di incertezza. Plotters offre una soluzione facile con la sua funzione ErrorBar, che consente agli utenti di aggiungere questi essenziali strumenti visivi a qualsiasi grafico specificando le coordinate x/y, le preferenze di colore/stile e fornendo i valori di errore pertinenti. Consideriamo il seguente frammento di codice:

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Grafico con barre di errore verticali", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(1f32..7f32, 1f32..50f32)?;        let x = Array::range(1., 7., 0.1);    chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 0.1);")        .y_desc("y = f(x)")        .draw()?;    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, (*x as f32).powi(2))),        &GREEN    )).unwrap()        .label("y = x ^ 2")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &GREEN));      chart.draw_series(x.map(|x| {        ErrorBar::new_vertical(*x, (*x as f32).powi(2) - 1.5, (*x as f32).powi(2), (*x as f32).powi(2) + 1.4, RED.filled(), 2)    })).unwrap();    chart.configure_series_labels()        .background_style(&WHITE)        .border_style(&BLACK)        .draw()?;    Ok(())}).style("width: 100%")

In questo esempio, abbiamo scelto di visualizzare l’errore sull’asse y poiché è tipicamente più prevalente. L’immagine seguente è una rappresentazione visuale dei nostri dati e mostra chiaramente le barre di errore che circondano ciascun punto dati. Queste barre indicano l’intervallo di valori che è probabile che si trovi entro un certo livello di confidenza; barre più lunghe indicano una maggiore incertezza nella misurazione.

Tuttavia, può esserci occasione in cui visualizzare i dati di errore su entrambi gli assi sarebbe vantaggioso – specialmente quando si tratta di serie temporali o dati sperimentali contenenti più variabili indipendenti. In tali casi, utilizzando il metodo ErrorBar::new_horizontal e passando un array di errori sull’asse x (analogo a quanto fatto per gli errori sull’asse y) sarà sufficiente.

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Grafico con barre di errore orizzontali", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(1f32..7f32, 1f32..50f32)?;        let x = Array::range(1., 7., 0.1);    chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 0.1);")        .y_desc("y = f(x)")        .draw()?;    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, (*x as f32).powi(2))),        &GREEN    )).unwrap()        .label("y = x ^ 2")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &GREEN));      chart.draw_series(x.map(|x| {        ErrorBar::new_horizontal((*x as f32).powi(2), *x - 0.3, *x, *x + 0.3, RED.filled(), 2)    })).unwrap();    chart.configure_series_labels()        .background_style(&WHITE)        .border_style(&BLACK)        .draw()?;    Ok(())}).style("width: 100%")
Un singolo grafico con barre di errore orizzontali (immagine dell'autore)

Incorporando tali elementi nelle vostre visualizzazioni – che siate uno scienziato che condivide i risultati di una ricerca o un analista aziendale che mostra i dati di vendita – il pubblico può comprendere meglio qualsiasi incertezza associata alle informazioni presentate. Pertanto, utilizzare questa funzionalità essenziale garantirà che i dettagli precisi siano trasmessi in modo accurato mantenendo al contempo la chiarezza nelle presentazioni senza confusione causata da errori nei dati rappresentati graficamente utilizzando le funzionalità di Error Bars di Plotters!

Grafico a dispersione

I grafici a dispersione sono uno strumento fondamentale per visualizzare i dati e ottenere informazioni sulla relazione tra due variabili. Plotters rende semplice la creazione di grafici a dispersione in Rust assegnando una variabile all’asse x e un’altra all’asse y, e tracciando ogni punto sulle rispettive coordinate. Manipolando i colori e le dimensioni dei punti, è possibile rappresentare dimensioni aggiuntive all’interno del dataset.

Il principale vantaggio nell’utilizzo dei grafici a dispersione è che essi rivelano modelli o cluster nei dati che potrebbero non essere evidenti solo da tabelle o grafici. Gli outlier sono anche facilmente identificabili mediante questo metodo.

Inoltre, questi grafici hanno una natura intuitiva che consente a chiunque, indipendentemente dall’esperienza statistica, di comprendere rapidamente le relazioni tra diversi aspetti, rendendoli strumenti di comunicazione utili nella presentazione dei risultati.

Il seguente frammento di codice genererà un grafico a dispersione di un campione di dati con distribuzione uniforme:

evcxr_figure((640, 480), |root| {    _ = root.fill(&WHITE);    let mut chart = ChartBuilder::on(&root)        .caption("Grafico a dispersione con distribuzione uniforme", ("Arial", 20).into_font())        .x_label_area_size(40)        .y_label_area_size(40)        .build_cartesian_2d(0f32..1f32, 0f32..1f32)?;    chart.configure_mesh()        .disable_x_mesh()        .disable_y_mesh()        .y_labels(5)        .x_label_formatter(&|x| format!("{:.1}", *x as f64 / 100.0))        .y_label_formatter(&|y| format!("{}%", (*y * 100.0) as u32))        .draw()?;    let _ = chart.draw_series(random_samples.iter().map(|(x,y)| Circle::new((*x,*y), 3, GREEN.filled())));        Ok(())}).style("width:100%")

Il grafico a dispersione prodotto è il seguente:

Un grafico a dispersione di campioni di dati con distribuzione uniforme (immagine dell'autore)

In sintesi, i grafici a dispersione offrono potenti capacità di visualizzazione che ci permettono di comprendere meglio i nostri dataset, offrendo modi semplici per condividere informazioni con gli altri, grazie principalmente alle funzioni della libreria di Plotters disponibili nell’ambiente di programmazione Rust!

Istogramma

Gli istogrammi sono un prezioso strumento quando si tratta di analizzare la distribuzione dei dati. Offrono una rappresentazione visiva di come le informazioni sono distribuite tra diverse categorie o intervalli, semplificando la comprensione e l’interpretazione di complessi insiemi di dati. Plotters semplifica questo processo utilizzando la funzione Histogram::vertical con array lineari che raggruppano insieme i punti dati in barre che rappresentano la frequenza per dimensione dell’intervallo.

Ad esempio, se dobbiamo tracciare una distribuzione uniforme generata casualmente, creare istogrammi visualizzerà la frequenza di ogni possibile risultato in dettaglio, rivelando eventuali pattern o tendenze presenti nel dataset. L’analisi di questi grafici può aiutare a scoprire informazioni preziose sulle distribuzioni sottostanti, come la demografia dei gruppi di età nelle popolazioni, i livelli di esposizione alla luce catturati nelle fotografie o le precipitazioni mensili osservate nelle città.

Il seguente frammento di codice è un esempio di tracciamento di campioni di dati di distribuzione uniforme generati casualmente:

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Istogramma", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(0u32..100u32, 0f64..0.5f64)?;    chart.configure_mesh()        .disable_x_mesh()        .disable_y_mesh()        .y_labels(5)        .x_label_formatter(&|x| format!("{:.1}", *x as f64 / 100.0))        .y_label_formatter(&|y| format!("{}%", (*y * 100.0) as u32))        .draw()?;    let hist = Histogram::vertical(&chart)        .style(RED.filled())        .margin(0)        .data(random_samples.iter().map(|(x,_)| ((x*100.0) as u32, 0.01)));    let _ = chart.draw_series(hist);        Ok(())}).style("width:100%")

L’istogramma prodotto è il seguente:

Un istogramma di campioni di dati distribuiti in modo uniforme (immagine dell'autore)

In sintesi, gli istogrammi forniscono strumenti potenti per comprendere vari set di dati e identificare con precisione i fattori critici che li influenzano nel tempo. Utilizzando le funzionalità di Plotters come dimensioni personalizzabili del bin adattate specificamente alle nostre esigenze, otteniamo una maggiore flessibilità nell’interpretazione di grandi quantità di informazioni in modo rapido senza compromettere l’accuratezza!

Conclusioni

Foto di Aaron Burden su Unsplash

Questo articolo ha sottolineato l’importanza delle visualizzazioni e come Plotters possa essere personalizzato per soddisfare diverse esigenze. Plotters si è rivelato prezioso nella creazione di diversi tipi di grafici, come grafici a linea singola o multilinea, scatter plot e istogrammi. Inoltre, abbiamo appreso come personalizzare funzionalità come scelte di layout per linee di colore, marcatori, legende, ecc.

Con la nuova conoscenza acquisita, puoi navigare con sicurezza tra le varie funzionalità di Plotters. Sfruttare efficacemente questi metodi migliorerà la comprensione dei dati e consentirà una comunicazione migliore dei risultati.

Nella prossima serie di articoli, in particolare nella parte 2, esploreremo affascinanti visualizzazioni dei dati, tra cui, ma non solo, grafici a torta e visualizzazioni 3D. L’obiettivo è quello di permetterti di diventare un abile narratore visivo dei tuoi dati, rivelando insight nascosti come mai prima d’ora!

Nota finale

Foto di Nick Morrison su Unsplash

Alla conclusione di questo tutorial, desidero esprimere il mio sincero apprezzamento a tutti coloro che hanno dedicato tempo ed energia per completarlo. È stato un vero piacere dimostrare con te le straordinarie capacità del linguaggio di programmazione Rust.

Essendo appassionato di data science, ti prometto che scriverò almeno un articolo completo ogni settimana o giù di lì su argomenti correlati. Se sei interessato a rimanere aggiornato sul mio lavoro, considera di connetterti con me su vari social media o contattami direttamente se hai bisogno di altre assistenze.

Grazie!

Risorse

GitHub – wiseaidev/rust-data-analysis: Il corso definitivo di analisi dei dati con Rust.

Il corso definitivo di analisi dei dati con Rust. Contribuisci allo sviluppo di wiseaidev/rust-data-analysis creando un…

github.com

plotters – Rust

Plotters – Una libreria di disegno Rust che si concentra sulla rappresentazione grafica dei dati per applicazioni WASM e native 🦀📈🚀

docs.rs

evcxr-jupyter-integration

Poiché evcxr utilizza solo immagini SVG e tutti i tipi di serie, non abbiamo bisogno di altri tipi di backend. Pertanto, dovremmo inserire…

plotters-rs.github.io