Plotly e Pandas Unire le Forze per una Efficace Visualizzazione dei Dati
Plotly e Pandas una Visualizzazione Efficace dei Dati
Una guida rapida ispirata a Storytelling with Data
“Le mie abilità di visualizzazione dei dati sono scarse. Il mio pubblico sembra poco impressionato dal mio lavoro e, peggio ancora, non è convinto.”
C’è stato un tempo in cui molti di noi si sono imbattuti in questo problema. A meno che tu non sia dotato o abbia seguito un corso di design in precedenza, potrebbe essere piuttosto impegnativo e richiedere molto tempo produrre grafici visivamente estetici che siano intuitivi per il pubblico allo stesso tempo.
Ecco cosa mi è venuto in mente allora: voglio essere più intenzionale nel creare i miei grafici in modo che trasmettano informazioni al mio pubblico in modo intuitivo. Con questo intendo non far loro sforzare la mente e consumare eccessivamente il loro tempo per capire cosa sta succedendo.
Prima pensavo che passare da Matplotlib a Seaborn e infine a Plotly risolvesse il problema dell’estetica. In effetti, mi sbagliavo. La visualizzazione non riguarda solo l’estetica. Di seguito sono riportate due visualizzazioni che ho cercato di replicare da Storytelling with Data¹ di Cole Nussbaumer Knaflic che mi hanno davvero ispirato a cambiare il mio approccio alla visualizzazione. Sono pulite, eleganti e mirate. In questo articolo cercheremo di replicare questi grafici!
- L’ottimizzazione dietro SVM Forma Primale e Duale
- Async per LangChain e LLMs
- Crea la tua applicazione ChatGPT utilizzando Spring Boot
![Immagine di Autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*qjbILTC2uBEYU_C8vkG8jg.png)
Ecco il messaggio principale di questo post. Se stai cercando una spiegazione approfondita dei concetti che stanno dietro a una grande visualizzazione, dai un’occhiata a Storytelling with Data¹, ogni pagina è un gioiello che vale il tuo tempo. Se stai cercando consigli specifici sugli strumenti e pratici, sei nel posto giusto. Cole ha menzionato all’inizio del suo libro che i consigli che ha presentato sono universali e indipendenti dagli strumenti, anche se ha ammesso di aver creato gli esempi nel libro utilizzando Excel. Alcune persone, me compreso, non sono fan di Excel e degli strumenti trascina-e-rilascia per molte ragioni. Alcuni preferiscono creare visualizzazioni utilizzando Python, R e altri linguaggi di programmazione. Se fai parte di questo segmento e utilizzi Python come tuo strumento principale, allora questo articolo fa al caso tuo.
Tabella dei contenuti
- Chaining—Pandas Plot
- Grafico a barre orizzontale
- Grafico a linee
- Bonus: Grafico numerico
Chaining—Pandas Plot
Se sei un esperto o un giocatore esperto nell’utilizzo di Pandas per la manipolazione dei dati, potresti incontrare o addirittura adottare l’idea di “Chaining” tu stesso. In breve, il chaining consente al tuo codice di essere molto più leggibile, più facile da debuggare e pronto per la produzione. Ecco un semplice esempio di ciò a cui mi riferisco. Non devi leggere riga per riga, dai solo un’occhiata veloce per capire l’idea dietro “Chaining”. Ogni passo è chiaro e facile da spiegare, e il codice è ben organizzato senza variabili intermedie superflue.
(epl_10seasons .rename(columns=lambda df_: df_.strip()) .rename(columns=lambda df_: re.sub('\W+|[!,*)@#%(&$_?.^]', '_', df_)) .pipe(lambda df_: df_.astype({column: 'int8' for column in (df_.select_dtypes("integer").columns.tolist())})) .pipe(lambda df_: df_.astype({column: 'category' for column in (df_.select_dtypes("object").columns.tolist()[:-1])})) .assign(match_date=lambda df_: pd.to_datetime(df_.match_date, infer_datetime_format=True)) .assign(home_team=lambda df_: np.where((df_.home_team == "Arsenal"), "The Gunners", df_.home_team), away_team=lambda df_: np.where((df_.away_team == "Arsenal"), "The Gunners", df_.away_team), month=lambda df_: df_.match_date.dt.month_name()) .query('home_team == "The Gunners"'))
Questo è fantastico, ma sapevi che puoi continuare il processo di chaining per creare anche grafici di visualizzazione di base? Pandas Plot, per impostazione predefinita, utilizza Matplotlib come backend a questo scopo. Vediamo come funziona e riproduciamo alcuni degli esempi creati da Cole nel suo libro.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.graph_objects as go
%matplotlib inline
pd.options.plotting.backend = 'plotly'
df = pd.DataFrame({"preoccupazioni": ["La potenza del motore è inferiore alle aspettative",
"Le gomme fanno rumore eccessivo durante la guida",
"Il motore emette rumori anomali / eccessivi",
"Preoccupazioni sul materiale del sedile",
"Rumore eccessivo del vento",
"Esitazione o ritardo durante il cambio",
"Il sistema Bluetooth ha una scarsa qualità audio",
"Il sistema di sterzo / ruota ha troppo gioco",
"Il sistema Bluetooth è difficile da usare",
"Controlli audio / intrattenimento / navigazione del sedile anteriore"
],
"preoccupazioni per 1.000": [12.9, 12.3, 11.6, 11.6, 11.0, 10.3, 10.0, 8.8, 8.6, 8.2]
},
index=list(range(0,10,1)))
Abbiamo un DataFrame che appare così.
![Immagine di Autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*Yc-15FA3e_xYNAx828z0hQ.png)
(df .plot .barh())
Questa è il modo più veloce per generare un grafico di visualizzazione di base. Concatenando l’attributo .plot
e il metodo .barh
direttamente da un DataFrame, otteniamo il grafico sottostante.
![Immagine di Autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*kJWveVd2j_ovpztlrFgK8A.png)
Tieni a freno la tua reazione e il tuo giudizio se pensi che il grafico sopra non superi il controllo estetico. Infatti, sembra brutto, per non dire di peggio. Diamo un po’ di pepe e facciamo meglio. Ecco il trucco, passa il tuo backend di tracciamento di Pandas da Matplotlib a Plotly per la magia che sta per svelarsi.
pd.options.plotting.backend = 'plotly'
Potresti chiederti: “Perché lo cambio a Plotly? Matplotlib non è in grado di fare la stessa cosa?” Beh, ecco la differenza.
Se usiamo il backend di Matplotlib in Pandas, restituisce un oggetto Axes, prova a verificarlo usando il metodo type()
integrato. Questo è fantastico perché l’oggetto Axes ci consente di accedere a metodi per modificare ulteriormente il nostro grafico. Dai un’occhiata a questa documentazione² per i possibili metodi da eseguire sull’oggetto Axes. Prendiamone uno per illustrare rapidamente.
(df .plot .barh() .set_xlabel("preoccupazioni per 1.000"))
![Immagine di Autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*9nEPtP9zbuEG4eq9gyA8pg.png)
Siamo riusciti a impostare l’etichetta dell’asse x su “preoccupazioni per 1.000”, ma nel farlo, restituiamo un oggetto Text e perdiamo il nostro prezioso oggetto Axis che ci consente di accedere a metodi preziosi per modificare ulteriormente il nostro grafico. Peccato!
Ecco un’alternativa per aggirare la limitazione sopra descritta:
(df .plot .barh(xlabel="Preoccupazioni per 1.000", ylabel="Preoccupazioni", title="Le 10 principali preoccupazioni di design"))
![Immagine di Autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*o98laSWZqPFSZY05aN9Q7Q.png)
Tuttavia, siamo ancora in grado di apportare modifiche estensive poiché l’integrazione è piuttosto limitata dall’implementazione di Pandas qui.
Plotly, d’altra parte, non restituisce un oggetto Axes. Restituisce un oggetto go.Figure
. La differenza qui è che i metodi responsabili dell’aggiornamento dei grafici restituiscono anche un oggetto go.Figure
, che ti consente di continuare a concatenare il tuo metodo per aggiornare ulteriormente il tuo grafico. Proviamolo!
A proposito, nel caso ti stessi chiedendo come ottengo le combinazioni di metodi e argomenti qui sotto, sono tutti disponibili nella documentazione ufficiale qui³.
Ecco alcuni metodi importanti per iniziare: .update_traces
, .add_traces
, .update_layout
, .update_xaxes
, .update_yaxes
, .add_annotation
, .update_annotations
.
Grafico a Barre Orizzontali
Definiamo un set di tabelle di colori per la nostra visualizzazione qui sotto.
GRAY1, GRAY2, GRAY3 = '#231F20', '#414040', '#555655'GRAY4, GRAY5, GRAY6 = '#646369', '#76787B', '#828282'GRAY7, GRAY8, GRAY9, GRAY10 = '#929497', '#A6A6A5', '#BFBEBE', '#FFFFFF'BLUE1, BLUE2, BLUE3, BLUE4, BLUE5 = '#25436C', '#174A7E', '#4A81BF', '#94B2D7', '#94AFC5'BLUE6, BLUE7 = '#92CDDD', '#2E869D'RED1, RED2, RED3 = '#B14D4A', '#C3514E', '#E6BAB7'GREEN1, GREEN2 = '#0C8040', '#9ABB59'ORANGE1, ORANGE2, ORANGE3 = '#F36721', '#F79747', '#FAC090'gray_palette = [GRAY1, GRAY2, GRAY3, GRAY4, GRAY5, GRAY6, GRAY7, GRAY8, GRAY9, GRAY10]blue_palette = [BLUE1, BLUE2, BLUE3, BLUE4, BLUE5, BLUE6, BLUE7]red_palette = [RED1, RED2, RED3]green_palette = [GREEN1, GREEN2]orange_palette = [ORANGE1, ORANGE2, ORANGE3]sns.set_style("darkgrid")sns.set_palette(gray_palette)sns.palplot(sns.color_palette())
![Immagine di Autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*dLVVMW_VPpiS8FnJNIAmcg.png)
Qui, vogliamo evidenziare le preoccupazioni che sono pari o superiori al 10 percento definendo un colore separato.
color = np.array(['rgb(255,255,255)']*df.shape[0])color[df .set_index("preoccupazioni", drop=True) .iloc[::-1] ["preoccupazioni per 1.000"]>=10] = red_palette[0]color[df .set_index("preoccupazioni", drop=True) .iloc[::-1] ["preoccupazioni per 1.000"]<10] = gray_palette[4]
Poi creiamo il grafico direttamente dal DataFrame.
(df .set_index("preoccupazioni", drop=True) .iloc[::-1] .plot .barh() .update_traces(marker=dict(color=color.tolist())))
![Immagine di Autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*h1jWx76zntmiHDpr1r75nQ.png)
Aggiornando il layout otteniamo quanto segue. Qui, specifichiamo il template, aggiungiamo un titolo e un margine al nostro grafico, e specifichiamo la dimensione del nostro oggetto figura. Commentiamo le annotazioni per il momento.
(df .set_index("preoccupazioni", drop=True) .iloc[::-1] .plot .barh() .update_traces(marker=dict(color=color.tolist())) .update_layout(template="plotly_white", title=dict(text="<b>Top 10 preoccupazioni di design</b> <br><sup><i>preoccupazioni per 1.000</i></sup>", font_size=30, font_color=gray_palette[4]), margin=dict(l=50, r=50, b=50, t=100, pad=20), width=1000, height=800, showlegend=False, #annotations=annotations ))
![Immagine dell'autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*w3jhmT-29N28b-CAamQ2kw.png)
Aggiornando le proprietà degli assi x e y otteniamo quanto segue.
(df .set_index("preoccupazioni", drop=True) .iloc[::-1] .plot .barh() .update_traces(marker=dict(color=color.tolist())) .update_layout(template="plotly_white", title=dict(text="<b>Top 10 preoccupazioni di design</b> <br><sup><i>preoccupazioni per 1.000</i></sup>", font_size=30, font_color=gray_palette[4]), margin=dict(l=50, r=50, b=50, t=100, pad=20), width=1000, height=800, showlegend=False, #annotations=annotations ) .update_xaxes(title_standoff=10, showgrid=False, visible=False, tickfont=dict( family='Arial', size=16, color=gray_palette[4],), title="") .update_yaxes(title_standoff=10, tickfont=dict( family='Arial', size=16, color=gray_palette[4],), title=""))
![Immagine dell'autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*J31erz8ETy79B1VtR7xBSQ.png)
Ultimo ma non meno importante, aggiungeremo alcune annotazioni al nostro grafico. Qui abbiamo alcune annotazioni – aggiungere etichette dati al grafico a barre orizzontali e una nota a piè di pagina. Facciamolo insieme. Per prima cosa, definiamo le annotazioni in una cella separata.
annotations = []y_s = np.round(df["preoccupazioni per 1.000"], decimals=2)# Aggiunta etichette datifor yd, xd in zip(y_s, df.preoccupazioni): # etichettatura del patrimonio netto della barra annotations.append(dict(xref='x1', yref='y1', y=xd, x=yd - 1, text=str(yd) + '%', font=dict(family='Arial', size=16, color=gray_palette[-1]), showarrow=False)) # Aggiunta annotazioni al sorgenteannotations.append(dict(xref='paper', yref='paper', x=-0,72, y=-0,050, text='Fonte: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco' '<br>laboris nisi ut aliquip ex ea commodo consequat.', font=dict(family='Arial', size=10, color=gray_palette[4]), showarrow=False, align='left'))
(df .set_index("preoccupazioni", drop=True) .iloc[::-1] .plot .barh() .update_traces(marker=dict(color=color.tolist())) .update_layout(template="plotly_white", title=dict(text="<b>Top 10 preoccupazioni di design</b> <br><sup><i>preoccupazioni per 1.000</i></sup>", font_size=30, font_color=gray_palette[4]), margin=dict(l=50, r=50, b=50, t=100, pad=20), width=1000, height=800, showlegend=False, annotations=annotations ) .update_xaxes(title_standoff=10, showgrid=False, visible=False, tickfont=dict( family='Arial', size=16, color=gray_palette[4],), title="") .update_yaxes(title_standoff=10, tickfont=dict( family='Arial', size=16, color=gray_palette[4],), title=""))
![Immagine dell'autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*P7dH0pYW463aD_Z_QcGU7w.png)
Non è questo un grafico molto migliore rispetto alla versione predefinita iniziale? Continuiamo a esplorare un altro grafico popolare – il grafico a linea.
Un piccolo avviso che l’esempio sottostante è più complicato di quello precedente. Tuttavia, l’idea rimane la stessa.
Grafico a Linee
Diamo un’occhiata veloce alla libreria di plot predefinita di Matplotlib per il grafico a linea.
pd.options.plotting.backend = 'matplotlib'df = pd.DataFrame({"Ricevuti": [160,184,241,149,180,161,132,202,160,139,149,177], "Elaborati":[160,184,237,148,181,150,123,156,126,104,124,140]}, index=['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'])(df .plot .line());
![Immagine di Autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*jUC45wBpKudvAvtSAHdjrg.png)
Cambiamo il nostro plot backend in Plotly!
pd.options.plotting.backend = 'plotly'(df .plot(x=df.index, y=df.Ricevuti, labels=dict(index="", value="Numero di ticket"),))
Dopo aver cambiato il plot backend di Pandas in Plotly, il codice sopra ci restituisce quanto segue. Qui, iniziamo tracciando solo la Serie Ricevuti.
![Immagine di Autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*tLARESy_ripuTDRxyd8CAg.png)
Aggiorniamo la proprietà line concatenando ulteriormente il metodo precedente. Qui, modifichiamo il colore, la larghezza e posizioniamo i marcatori sui punti dei dati.
(df .plot(x=df.index, y=df.Ricevuti, labels=dict(index="", value="Numero di ticket"),) .update_traces(go.Scatter(mode='lines+markers+text', line={"color": gray_palette[4], "width":4}, marker=dict(size=12)),))
![Immagine di Autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*Xx1vVhfTV6JvbusDcTZuEw.png)
Aggiungiamo la Serie Elaborati al grafico!
(df .plot(x=df.index, y=df.Ricevuti, labels=dict(index="", value="Numero di ticket"),) .update_traces(go.Scatter(mode='lines+markers+text', line={"color": gray_palette[4], "width":4}, marker=dict(size=12)),) .add_traces(go.Scatter(x=df.index, #Aggiungi colonna Elaborati y=df.Elaborati, mode="lines+markers+text", line={"color": blue_palette[0], "width":4}, marker=dict(size=12))))
![Immagine di Autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*swKUSdDZD7ZGwwQpQHUfmw.png)
Aggiungiamo una linea verticale all’indice Maggio per mostrare il punto in cui le due linee iniziano a divergere.
(df .plot(x=df.index, y=df.Ricevuti, labels=dict(index="", value="Numero di ticket"),) .update_traces(go.Scatter(mode='lines+markers+text', line={"color": gray_palette[4], "width":4}, marker=dict(size=12)),) .add_traces(go.Scatter(x=df.index, #Aggiungi colonna Elaborati y=df.Elaborati, mode="lines+markers+text", line={"color": blue_palette[0], "width":4}, marker=dict(size=12))) .add_traces(go.Scatter(x=["Maggio", "Maggio"], #Aggiungi vline y=[0,230], fill="toself", mode="lines", line_width=0.5, line_color= gray_palette[4])))
![Immagine dell'autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*_6m076Z8353DZnfOM-klWA.png)
Successivamente, aggiorniamo il layout generale cambiando lo sfondo in bianco e aggiungendo il titolo, il margine e alcuni altri elementi. Per le annotazioni, le commenteremo per il momento.
(df .plot(x=df.index, y=df.Received, labels=dict(index="", value="Numero di ticket"),) .update_traces(go.Scatter(mode='lines+markers+text', line={"color": gray_palette[4], "width":4}, marker=dict(size=12)),) .add_traces(go.Scatter(x=df.index, #Aggiungi colonna Processed y=df.Processed, mode="lines+markers+text", line={"color": blue_palette[0], "width":4}, marker=dict(size=12))) .add_traces(go.Scatter(x=["Maggio", "Maggio"], #Aggiungi vline y=[0,230], fill="toself", mode="lines", line_width=0.5, line_color= gray_palette[4])) .update_layout(template="plotly_white", title=dict(text="<b>Si prega di approvare l'assunzione di 2 FTE</b> <br><sup>per sostituire quelli che hanno lasciato l'anno scorso</sup> <br>Volume di ticket nel tempo <br><br><br>", font_size=30,), margin=dict(l=50, r=50, b=100, t=200,), width=900, height=700, yaxis_range=[0, 300], showlegend=False, #annotations=right_annotations, ))
![Immagine dell'autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*E9Y44EwldNR966lX_zDJPw.png)
Successivamente, effettueremo un aggiornamento sia degli assi x che degli assi y.
(df .plot(x=df.index, y=df.Received, labels=dict(index="", value="Numero di ticket"),) .update_traces(go.Scatter(mode='lines+markers+text', line={"color": gray_palette[4], "width":4}, marker=dict(size=12)),) .add_traces(go.Scatter(x=df.index, #Aggiungi colonna Processed y=df.Processed, mode="lines+markers+text", line={"color": blue_palette[0], "width":4}, marker=dict(size=12))) .add_traces(go.Scatter(x=["Maggio", "Maggio"], #Aggiungi vline y=[0,230], fill="toself", mode="lines", line_width=0.5, line_color= gray_palette[4])) .update_layout(template="plotly_white", title=dict(text="<b>Si prega di approvare l'assunzione di 2 FTE</b> <br><sup>per sostituire quelli che hanno lasciato l'anno scorso</sup> <br>Volume di ticket nel tempo <br><br><br>", font_size=30,), margin=dict(l=50, r=50, b=100, t=200,), width=900, height=700, yaxis_range=[0, 300], showlegend=False, #annotations=right_annotations, ) .update_xaxes(dict(range=[0, 12], showline=True, showgrid=False, linecolor=gray_palette[4], linewidth=2, ticks='', tickfont=dict( family='Arial', size=13, color=gray_palette[4], ), )) .update_yaxes(dict(showline=True, showticklabels=True, showgrid=False, ticks='outside', linecolor=gray_palette[4], linewidth=2, tickfont=dict( family='Arial', size=13, color=gray_palette[4], ), title_text="Numero di ticket" )))
![Immagine dell'autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*WOfE7Ozp5GSxU7RhO1i2YA.png)
Ultimo ma non meno importante, aggiungeremo alcune annotazioni al nostro grafico. Qui abbiamo alcune annotazioni: aggiungere etichette al grafico a linee (Received, Processed), oltre che aggiungere etichette ai punti dello scatter plot, che potrebbe essere un po’ complicato. Facciamolo insieme. Prima di tutto, definiamo le annotazioni in una cella separata.
y_data = df.to_numpy()colors = [gray_palette[3], blue_palette[0]]labels = df.columns.to_list()right_annotations = []# Aggiungere etichette alla lineaper y_trace, label, color in zip(y_data[-1], labels, colors): right_annotations.append(dict(xref='paper', x=0.95, y=y_trace, xanchor='left', yanchor='middle', text=label, font=dict(family='Arial',size=16,color=color), showarrow=False))# Aggiungere etichette ai punti scatterscatter_annotations = []y_received = [each for each in df.Received]y_processed = [float(each) for each in df.Processed]x_index = [each for each in df.index]y_r = np.round(y_received)y_p = np.rint(y_processed)for ydn, yd, xd in zip(y_r[-5:], y_p[-5:], x_index[-5:]): scatter_annotations.append(dict(xref='x2 domain', yref='y2 domain', y=ydn, x=xd, text='{:,}'.format(ydn), font=dict(family='Arial',size=16,color=gray_palette[4]), showarrow=False, xanchor='center', yanchor='bottom', )) scatter_annotations.append(dict(xref='x2 domain', yref='y2 domain', y=yd, x=xd, text='{:,}'.format(yd), font=dict(family='Arial',size=16,color=blue_palette[0]), showarrow=False, xanchor='center', yanchor='top', ))
Dopo aver definito le annotazioni, è sufficiente inserire la variabile di annotazione nel metodo di concatenazione come segue.
(df .plot(x=df.index, y=df.Received, labels=dict(index="", value="Numero di ticket"),) .update_traces(go.Scatter(mode='lines+markers+text', line={"color": gray_palette[4], "width":4}, marker=dict(size=12)),) .add_traces(go.Scatter(x=df.index, #Aggiungi colonna Processed y=df.Processed, mode="lines+markers+text", line={"color": blue_palette[0], "width":4}, marker=dict(size=12))) .add_traces(go.Scatter(x=["Maggio", "Maggio"], #Aggiungi vline y=[0,230], fill="toself", mode="lines", line_width=0.5, line_color= gray_palette[4])) .update_layout(template="plotly_white", title=dict(text="<b>Si prega di approvare l'assunzione di 2 FTE</b> <br><sup>per sostituire coloro che hanno lasciato l'anno scorso</sup> <br>Volume dei ticket nel tempo <br><br><br>", font_size=30,), margin=dict(l=50, r=50, b=100, t=200,), width=900, height=700, yaxis_range=[0, 300], showlegend=False, annotations=right_annotations, ) .update_layout(annotations=scatter_annotations * 2) .update_xaxes(dict(range=[0, 12], showline=True, showgrid=False, linecolor=gray_palette[4], linewidth=2, ticks='', tickfont=dict( family='Arial', size=13, color=gray_palette[4], ), )) .update_yaxes(dict(showline=True, showticklabels=True, showgrid=False, ticks='outside', linecolor=gray_palette[4], linewidth=2, tickfont=dict( family='Arial', size=13, color=gray_palette[4], ), title_text="Numero di ticket" )) .add_annotation(dict(text="<b>2 dipendenti hanno lasciato a maggio.</b> Ci siamo quasi tenuti al passo con il volume in entrata <br>nei due mesi successivi, ma siamo rimasti indietro con l'aumento ad agosto <br>e non siamo stati in grado di recuperare da allora.", font_size=18, align="left", x=7.5, y=265, showarrow=False)) .add_annotation(dict(xref='paper', yref='paper', x=0.5, y=-0.15, text='Fonte: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco' '<br>laboris nisi ut aliquip ex ea commodo consequat.', font=dict(family='Arial', size=10, color='rgb(150,150,150)'), showarrow=False, align='left')) .update_annotations(yshift=0) .show())
![Immagine dell'autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*3BVhpbC1qvhvAu5uSwVmeg.png)
Bonus: Tabella dei Numeri
Congratulazioni per essere arrivato a questa parte dell’articolo! Ecco un ulteriore grafico che puoi portare via! Qui stiamo creando una tabella per rappresentare esteticamente un numero da solo. In breve, è a questo che mi riferisco.
![Immagine dell'autore](https://miro.medium.com/v2/resize:fit:640/format:webp/1*KSYe9i88gwjB1jHBWx8Waw.png)
Dato che questo non è il risultato di un DataFrame, possiamo iniziare creando un oggetto vuoto go.Figure
da zero, quindi gradualmente aggiungere le annotazioni. Infine, aggiorniamo il layout di conseguenza.
(go .Figure() # Creare un'immagine vuota .add_annotation( x=0.0, y=1, text='Il programma pilota è stato un successo', showarrow=False, font={'size': 36, 'color': 'white'}, bgcolor=gray_palette[-3], bordercolor='gray', borderwidth=0, xref='paper', yref='paper', xanchor='left', yanchor='top', align='left', ax=0, ay=-10 ) .add_annotation( x=-1.0, # Coordinata X della posizione del testo y=3.0, # Coordinata Y della posizione del testo text="Dopo il programma pilota,", # Contenuto del testo showarrow=False, # Nascondi la freccia font=dict(size=20, color=blue_palette[1]), # Personalizza la dimensione del font xanchor='left', yanchor='top', align='left', ) .add_annotation( x=-1.0, # Coordinata X della posizione del testo y=1.6, # Coordinata Y della posizione del testo text="<b>68%</b>", # Contenuto del testo showarrow=False, # Nascondi la freccia font=dict(size=160, color=blue_palette[1]), # Personalizza la dimensione del font xanchor='left', align='left', ) .add_annotation( x=-1.0, # Coordinata X della posizione del testo y=0.2, # Coordinata Y della posizione del testo text="<b>dei bambini ha mostrato interesse per la scienza,</b>", # Contenuto del testo showarrow=False, # Nascondi la freccia font=dict(size=20, color=blue_palette[1]), # Personalizza la dimensione del font xanchor='left', align='left', ) .add_annotation( x=-1.0, # Coordinata X della posizione del testo y=-0.2, # Coordinata Y della posizione del testo text="rispetto al 44% all'inizio del programma.", # Contenuto del testo showarrow=False, # Nascondi la freccia font=dict(size=20, color=gray_palette[-3]), # Personalizza la dimensione del font xanchor='left', align='left', ) .add_annotation( x=-1.0, # Coordinata X della posizione del testo y=-0.7, # Coordinata Y della posizione del testo text='Sulla base di un sondaggio di 100 studenti condotto ' 'prima e dopo il programma pilota ' '(tasso di risposta del 100% su entrambi i sondaggi).', # Contenuto del testo showarrow=False, # Nascondi la freccia font=dict(size=10.5, color=gray_palette[-3]), # Personalizza la dimensione del font xanchor='left', align='left', ) .update_layout( xaxis=dict(visible=False), # Nascondi l'asse x yaxis=dict(visible=False), # Nascondi l'asse y margin=dict(l=0, r=0, b=0, t=0, pad=0), font=dict(size=26, color=gray_palette[-3]), # Personalizza la dimensione del font paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)' ) .show())
Postfazione
Ecco a te! La chiave è aggiornare e perfezionare il tuo grafico passo dopo passo fino a ottenere un risultato desiderabile. Ovviamente, ogni tecnica ha i suoi limiti. Se il tuo grafico sta diventando troppo complicato da produrre, potrebbe essere utile fare riferimento a Plotly Express o addirittura costruire tutto da zero utilizzando Plotly Graph Objects. Può sembrare difficile e poco familiare adottare questa tecnica all’inizio, ma continua a praticare e presto creerai bellissime visualizzazioni che hanno senso!
Se trovi qualcosa di utile in questo articolo, considera di seguirmi su VoAGI. Facile, un articolo a settimana per tenerti aggiornato e restare avanti!
Contattami!
- LinkedIn 👔
- Twitter 🖊
Riferimenti
- Storytelling with Data di Cole Nussbaumer Knaflic. https://www.storytellingwithdata.com/books
- API degli assi di Matplotlib. https://matplotlib.org/stable/api/axes_api.html
- Librerie di grafici Plotly. https://plotly.com/python/reference/