Come creare bellissimi grafici a barre con Seaborn e Matplotlib (inclusa l’animazione)

How to create beautiful bar charts with Seaborn and Matplotlib (including animation)

Tutorial sull’apprendimento automatico

Un tutorial sulla visualizzazione dei dati per Python

Grafico creato dall'autore

Ciao e benvenuti al mio primo tutorial su Matplotlib e Seaborn. Oggi vi mostrerò come trasformare un grafico a barre predefinito in una visualizzazione sorprendente con icone e animazioni.

Fammi sapere se ti piace questo tipo di contenuto. In tal caso, ne posso creare altri simili! 🙂

Puoi trovare il codice e i dati preelaborati in questa repository: simple-bar-chart-tutorial .

Cominciamo.

Passo 1: Creare un grafico a barre predefinito

Per questo tutorial, ho creato un semplice set di dati con il numero totale di stelle nel tempo per tre popolari framework di deep learning open-source ( Tensorflow , PyTorch , e Keras ).

Screenshot dell'autore

Ecco una semplice funzione che crea un semplice barplot per una riga nel DataFrame.

def create_bar_chart(row, color):        return sns.barplot(        y=row.index.str.capitalize().values,        x=row.values,        orient="h",        saturation=1,        color=color,        width=0.75,    )

Per creare una prima visualizzazione, eseguo il codice sopra in questo modo.

row = df.iloc[-1]fig = plt.figure(figsize=(12, 7))ax = create_bar_chart(row, color=bar_color)plt.title("Numero totale di stelle su GitHub")plt.tight_layout()plt.show()

Ecco il grafico a barre predefinito che ottengo se eseguo questa funzione per l’ultima riga del set di dati con il colore arancione.

Grafico a barre creato dall'autore

Nei passaggi successivi, creerò ulteriori funzioni che possiamo eseguire insieme al codice sopra per migliorare i grafici.

Cerchiamo di creare qualcosa di più bello.

Passo 2: Creazione di un tema

Innanzitutto, voglio creare una funzione che mi consente di testare diversi colori e font per i miei grafici.

Ci sono un sacco di metodi sia in Matplotlib che in Seaborn che ti permetteranno di modificare l’aspetto dei tuoi grafici.

Prefiro prima creare un tema utilizzando sns.set_style() . Ecco un frammento di codice che uso per creare rapidamente un nuovo tema.

def set_seaborn_style(font_family, background_color, grid_color, text_color):    sns.set_style({        "axes.facecolor": background_color,        "figure.facecolor": background_color,        "grid.color": grid_color,        "axes.edgecolor": grid_color,        "axes.grid": True,        "axes.axisbelow": True,                "axes.labelcolor": text_color,        "text.color": text_color,        "font.family": font_family,        "xtick.color": text_color,        "ytick.color": text_color,        "xtick.bottom": False,        "xtick.top": False,        "ytick.left": False,        "ytick.right": False,        "axes.spines.left": False,        "axes.spines.bottom": True,        "axes.spines.right": False,        "axes.spines.top": False,    })

Ci sono alcune opzioni in più per sns.set_style() , e potresti volerlo usare in modo diverso. Ma questa è la configurazione che funziona meglio per me.

Spesso vado su colorhunt.co o canva.com per ispirazione nella creazione di una combinazione di colori. Quando ho i colori di base che mi piacciono, vado su coolors.co se ne ho bisogno di qualche altro.

Ecco la palette di colori che ho creato per questo tutorial (e sì, mi piace il viola).

Screenshot dell'autore

Il mio carattere preferito è “PT Mono”, e con questa decisione, posso eseguire il seguente codice.

background_color = "#2F195F"grid_color = "#582FB1"bar_color = "#835ED4"text_color = "#eee"set_seaborn_style(font_family, background_color, grid_color, text_color)

Se ora eseguo il codice originale per creare un grafico a barre, ottengo il seguente.

Grafico a barre creato dall'autore

È un miglioramento chiaro, ma non abbastanza buono. Continuiamo formattando il testo del titolo e delle etichette degli assi.

Passaggio 3: Formattazione del testo

La prima cosa che noto è che le etichette degli assi devono essere più grandi. Tutte le informazioni visualizzate in un grafico dovrebbero essere facili da vedere immediatamente.

E non mi piace il modo in cui appaiono i numeri sull’asse x. Invece di scrivere 75000, voglio scrivere 75K per ottenere un aspetto meno intimidatorio.

Ecco perché ho creato questa funzione.

def format_axes(ax):    ax.tick_params("x", labelsize=20, pad=16)    ax.tick_params("y", labelsize=20, pad=8)        plt.xticks(        ticks=ax.get_xticks()[:-1],        labels=["{}K".format(int(x / 1000)) for x in ax.get_xticks()[:-1]]    )

Per il titolo, aggiungo parametri per aumentare la dimensione del carattere e regolare la posizione.

Ecco il codice per creare il grafico con le mie nuove modifiche.

row = df.iloc[-1]fig = plt.figure(figsize=(12, 7))ax = create_bar_chart(row, color=bar_color)# Nuova funzioneformat_axes(ax)plt.title("Numero totale di stelle su GitHub", fontsize=34, y=1.2, x=0.46)plt.tight_layout()plt.show()

Ecco il risultato.

Grafico a barre creato dall'autore

Comincia a sembrare piuttosto buono, ma ora è il momento di aggiungere un po’ di magia con le icone.

Passaggio 4: Aggiunta di icone

Aggiungere immagini e icone ai grafici è divertente ma difficile. Non è sempre facile posizionarle nel punto perfetto o con la dimensione ideale.

La seguente funzione aggiunge icone alla fine di ogni barra nel mio grafico utilizzando xycoords="data" e i valori dal mio DataFrame.

Il parametro boxstyle all’interno di bboxprops crea uno sfondo circolare bianco.

def add_bar_icons(ax, row, background_color, zoom, pad):    for index, (name, value) in enumerate(row.items()):         icon = plt.imread("./icons/{}.png".format(name.lower()))        image = OffsetImage(icon, zoom=zoom, interpolation="lanczos", resample=True, visible=True)        image.image.axes = ax        ax.add_artist(AnnotationBbox(            image, (value, index), frameon=True,            xycoords="data",            bboxprops={                "facecolor": "#fff",                "linewidth": 3,                "edgecolor": background_color,                "boxstyle": "circle, pad={}".format(pad),            }        ))

Voglio mettere l’icona su un cerchio bianco e aggiungere un bordo dello stesso viola scuro dello sfondo del grafico.

Fino ad ora, non ho trovato un buon modo per gestire il parametro zoom dinamicamente, quindi lo regolo manualmente per ottenere le dimensioni corrette.

Ora il mio codice per creare il grafico è così.

row = df.iloc[-1]fig = plt.figure(figsize=(12, 7))ax = create_bar_chart(row, color=bar_color)# Nuove funzioniformat_axes(ax)add_bar_icons(ax, row, background_color, zoom=0.09, pad=0.9)plt.title("Numero totale di stelle su GitHub", fontsize=34, y=1.2, x=0.46)plt.tight_layout()plt.show()

E questo è ciò che ottengo.

Grafico a barre creato dall'autore

Per aggiungere la stella, ho creato un’altra funzione che aggiunge un’icona personalizzata ovunque nel grafico usando xycoords="axes fraction" .

def add_icon(ax, icon_name, x, y, zoom):    icon = plt.imread("./icons/{}.png".format(icon_name))    image = OffsetImage(icon, zoom=zoom, interpolation="lanczos", resample=True, visible=True)    image.image.axes = ax    ax.add_artist(AnnotationBbox(        image, (x, y), frameon=False,        xycoords="axes fraction",    ))

In questo prossimo passaggio, faccio spazio per l’icona della stella aggiungendo spazi aggiuntivi al titolo e regolando i parametri x e y per posizionare l’icona nella posizione corretta.

row = df.iloc[-1]fig = plt.figure(figsize=(12, 7))ax = create_bar_chart(row, color=bar_color)# Nuove funzioniformat_axes(ax)add_bar_icons(ax, row, background_color, zoom=0.09, pad=0.9)add_icon(ax, "star", x=0.46, y=1.26, zoom=0.13)plt.title("Numero totale di stelle su GitHub", fontsize=34, y=1.2, x=0.46)plt.tight_layout()plt.show()

Ora il nostro grafico a barre sembra così, e siamo quasi finiti.

Grafico a barre creato dall'autore

Sembra eccellente, ma ora voglio trasformare il grafico in un formato più versatile.

E facciamo qualcosa riguardo a quel look compresso aggiungendo del padding.

Passaggio 5: Trasformare il grafico in un’immagine

Per questa parte, ho creato una funzione che prende la figura e la trasforma in un’immagine PIL. Un’immagine PIL è più facile da gestire per gli ultimi passaggi del nostro tutorial.

def create_image_from_figure(fig):    plt.tight_layout()    fig.canvas.draw()    data = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8)    data = data.reshape((fig.canvas.get_width_height()[::-1]) + (3,))    plt.close()         return Image.fromarray(data)

Ho anche creato la seguente funzione per aggiungere padding intorno al grafico.

def add_padding_to_chart(chart, left, top, right, bottom, background):    size = chart.size    image = Image.new("RGB", (size[0] + left + right, size[1] + top + bottom), background)    image.paste(chart, (left, top))    return image

Ecco una nuova versione del codice per generare il grafico in cui ho sostituito il classico plt.show() con i nostri nuovi metodi.

row = df.iloc[-1]fig = plt.figure(figsize=(12, 7))ax = create_bar_chart(row, color=bar_color)\plt.title("Numero totale di stelle su GitHub", fontsize=34, y=1.2, x=0.46)# Nuove funzioniformat_axes(ax)add_bar_icons(ax, row, background_color)add_icon(ax, "star", 0.46, 1.26)image = create_image_from_figure(fig)image = add_padding_to_chart(image, 0, 10, 10, 10, background_color)

E qui c’è il risultato.

Grafico a barre creato dall'autore

Fantastico!

Abbiamo trasformato il grafico a barre predefinito in qualcosa di molto più bello.

Concludiamo con una sezione bonus.

Bonus: Creazione di un’animazione

Poiché abbiamo separato il codice in funzioni riutilizzabili, è abbastanza facile creare un’animazione.

Tutto quello che dobbiamo fare è eseguire il codice più volte con valori diversi e unire i frame insieme.

Ecco un ciclo for in cui prendo 200 delle ultime 2000 righe nel dataset. Sto anche fissando l’asse x impostando xlim=(0, 185000) per evitare valori sfarfallanti.

images = []for i in tqdm.tqdm(range(1, 2000, 10)):    row = df.iloc[-i]    fig = plt.figure(figsize=(12, 7))    ax = create_bar_chart(row, color=bar_color)    ax.set(xlim=(0, 185000))    plt.title("Numero totale di stelle su GitHub", fontsize=34, y=1.2, x=0.46)    format_axes(ax)    add_bar_icons(ax, row, background_color, zoom=0.09, pad=0.9)    add_icon(ax, "star", 0.46, 1.26)    image = create_image_from_figure(fig)    image = add_padding_to_chart(image, 20, 20, 40, 0, background_color)    images.append(image)    images.reverse()

Successivamente, uso imageio per creare un GIF.

# Aggiungo alcuni duplicati dell'ultimo frame per creare un ritardoimages = images + [images[-1] for _ in range(20)]imageio.mimwrite('./animation.gif', images, duration=50)

Ecco il risultato.

Visualizzazione creata dall'autore

Questo segna la fine di questo tutorial, spero che ti sia piaciuto. Se sì, condividi questa storia e iscriviti al mio canale.

Dovresti anche seguirmi su Twitter: @oscarle3o

Grazie per aver letto.

A presto! 🙂