Introduzione: Perché la Visualizzazione dei Dati Conta (Davvero)
Se lavorate con i dati, lo sapete bene: i numeri da soli non bastano quasi mai. Puoi avere il dataset più completo del mondo, ma se non riesci a mostrare quello che hai trovato in modo chiaro, è come parlare una lingua che nessuno capisce. La visualizzazione dei dati è proprio quel ponte tra l'analisi grezza e l'intuizione — trasforma righe e colonne in qualcosa che il cervello elabora in un istante.
Che dobbiate presentare i risultati al vostro team, esplorare pattern nascosti in un dataset, o costruire una dashboard di monitoraggio in tempo reale, saper creare grafici efficaci è una competenza che fa la differenza.
Python, con il suo ecosistema di librerie, offre strumenti per ogni esigenza. In questa guida esploreremo a fondo le tre librerie più importanti — Matplotlib, Seaborn e Plotly — partendo dalle basi fino alle tecniche avanzate, inclusa la creazione di dashboard interattivi con Dash e Streamlit. Vedremo anche le novità di Matplotlib 3.10 e le tendenze più recenti del 2025-2026.
1. Matplotlib: Le Fondamenta della Visualizzazione in Python
Matplotlib è la libreria storica per la visualizzazione in Python — rilasciata nel lontano 2003 e ancora oggi, con la versione 3.10.x, è il fondamento su cui si basano molte altre librerie (Seaborn incluso). La sua forza? Una flessibilità praticamente totale: ogni singolo pixel di un grafico può essere personalizzato.
Onestamente, la curva di apprendimento non è la più dolce, ma una volta che ci si prende la mano, le possibilità sono infinite.
1.1 Installazione e Primi Passi
L'installazione è immediata:
pip install matplotlib
# oppure
conda install matplotlib
Creiamo il nostro primo grafico a linee:
import matplotlib.pyplot as plt
import numpy as np
# Generare dati di esempio
x = np.linspace(0, 2 * np.pi, 100)
y_sin = np.sin(x)
y_cos = np.cos(x)
# Creare il grafico
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(x, y_sin, label='Seno', color='#2196F3', linewidth=2)
ax.plot(x, y_cos, label='Coseno', color='#FF5722', linewidth=2, linestyle='--')
# Personalizzazione
ax.set_title('Funzioni Trigonometriche', fontsize=16, fontweight='bold')
ax.set_xlabel('Angolo (radianti)', fontsize=12)
ax.set_ylabel('Valore', fontsize=12)
ax.legend(fontsize=11)
ax.grid(True, alpha=0.3)
ax.set_xlim(0, 2 * np.pi)
plt.tight_layout()
plt.show()
Una cosa importante: notate l'uso dell'interfaccia orientata agli oggetti (fig, ax = plt.subplots()) invece della più semplice interfaccia procedurale (plt.plot()). Questa è la pratica consigliata per qualsiasi grafico non banale, perché vi dà un controllo molto più granulare su ogni elemento. Fidatevi, vi risparmierà un sacco di grattacapi.
1.2 Tipi di Grafici Essenziali
Matplotlib supporta decine di tipi di grafico. Ecco quelli che userete più spesso nella data science:
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
fig, axes = plt.subplots(2, 3, figsize=(16, 10))
# 1. Scatter plot
x = np.random.randn(200)
y = 0.5 * x + np.random.randn(200) * 0.5
axes[0, 0].scatter(x, y, alpha=0.6, c=y, cmap='viridis', s=40)
axes[0, 0].set_title('Scatter Plot')
# 2. Istogramma
dati = np.random.normal(100, 15, 1000)
axes[0, 1].hist(dati, bins=30, color='#4CAF50', edgecolor='white', alpha=0.8)
axes[0, 1].set_title('Istogramma')
# 3. Grafico a barre
categorie = ['Python', 'R', 'Julia', 'Scala', 'MATLAB']
valori = [85, 60, 35, 25, 40]
axes[0, 2].bar(categorie, valori, color=['#2196F3', '#4CAF50', '#9C27B0', '#FF9800', '#F44336'])
axes[0, 2].set_title('Grafico a Barre')
# 4. Box plot
dati_box = [np.random.normal(m, 1, 100) for m in [2, 3, 4, 3.5]]
axes[1, 0].boxplot(dati_box, labels=['Q1', 'Q2', 'Q3', 'Q4'])
axes[1, 0].set_title('Box Plot')
# 5. Grafico a torta
fette = [35, 25, 20, 15, 5]
etichette = ['pandas', 'NumPy', 'scikit-learn', 'Matplotlib', 'Altro']
axes[1, 1].pie(fette, labels=etichette, autopct='%1.1f%%', startangle=90)
axes[1, 1].set_title('Grafico a Torta')
# 6. Area plot
x = np.arange(10)
y1 = np.random.randint(5, 15, 10)
y2 = np.random.randint(3, 10, 10)
axes[1, 2].stackplot(x, y1, y2, labels=['Serie A', 'Serie B'], alpha=0.7)
axes[1, 2].legend(loc='upper left')
axes[1, 2].set_title('Area Plot Impilato')
plt.suptitle('Panoramica dei Grafici con Matplotlib', fontsize=18, fontweight='bold')
plt.tight_layout()
plt.show()
1.3 Novità di Matplotlib 3.10: subplot_mosaic e Altro
La versione 3.10, rilasciata a dicembre 2024, ha portato diverse novità interessanti. Tra queste spicca il nuovo ciclo di colori petroff10, progettato per essere sia esteticamente gradevole sia accessibile a persone con deficit della visione cromatica — un dettaglio che fa davvero la differenza quando si lavora su report destinati a un pubblico ampio. Sono state inoltre aggiunte tre nuove colormap divergenti: berlin, managua e vanimo.
Ma la funzionalità che personalmente trovo più utile è subplot_mosaic. Stabilizzata a partire dalla versione 3.7, permette di creare layout complessi di sottografici usando una sintassi visiva basata su arte ASCII. Basta guardare il codice per capire il layout, ed è fantastico:
import matplotlib.pyplot as plt
import numpy as np
# Definire il layout usando arte ASCII
layout = """
AAB
CDB
CDE
"""
fig, axes = plt.subplot_mosaic(
layout,
figsize=(14, 10),
gridspec_kw={'hspace': 0.3, 'wspace': 0.3}
)
np.random.seed(42)
# Grafico A: linee temporali
t = np.arange(100)
axes['A'].plot(t, np.cumsum(np.random.randn(100)), color='#1976D2')
axes['A'].set_title('A — Serie Temporale')
# Grafico B: istogramma verticale (span su 2 righe)
dati = np.random.exponential(2, 500)
axes['B'].hist(dati, bins=25, orientation='horizontal', color='#E91E63')
axes['B'].set_title('B — Distribuzione')
# Grafico C: heatmap (span su 2 righe)
matrice = np.random.rand(8, 8)
axes['C'].imshow(matrice, cmap='YlOrRd', aspect='auto')
axes['C'].set_title('C — Heatmap')
# Grafico D: scatter
axes['D'].scatter(np.random.randn(50), np.random.randn(50), c='#4CAF50', s=60)
axes['D'].set_title('D — Scatter')
# Grafico E: barre
axes['E'].barh(['α', 'β', 'γ', 'δ'], [4, 7, 3, 9], color='#FF9800')
axes['E'].set_title('E — Barre Orizzontali')
plt.suptitle('Layout Complesso con subplot_mosaic', fontsize=16, fontweight='bold')
plt.show()
Il vantaggio è duplice: la stringa ASCII rende immediatamente visivo il layout che volete ottenere, e il dizionario restituito vi permette di accedere a ciascun sottografico per nome (anziché per indice numerico). Il codice diventa molto più leggibile e manutenibile — provatelo e non tornerete più indietro.
2. Seaborn: Eleganza Statistica con Poco Codice
Seaborn è costruito sopra Matplotlib e fornisce un'interfaccia di alto livello per grafici statistici attraenti con pochissimo codice. Se Matplotlib è il coltellino svizzero, Seaborn è la penna stilografica: fa meno cose, ma quelle che fa le fa con una classe superiore.
La sua integrazione nativa con i DataFrame di pandas lo rende perfetto per l'analisi esplorativa dei dati (EDA).
2.1 Configurazione e Temi
pip install seaborn
Seaborn offre temi predefiniti che migliorano immediatamente l'estetica dei grafici:
import seaborn as sns
import matplotlib.pyplot as plt
# Temi disponibili: darkgrid, whitegrid, dark, white, ticks
sns.set_theme(style='whitegrid', palette='deep', font_scale=1.1)
# Palette personalizzate
palette_custom = sns.color_palette('husl', 8)
sns.palplot(palette_custom)
plt.title('Palette HUSL con 8 colori')
plt.show()
2.2 Grafici Statistici per l'EDA
Qui Seaborn dà il meglio di sé. Ecco un esempio completo con il dataset classico "tips" — uno di quei dataset che ogni data scientist conosce a memoria:
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
# Caricare dataset di esempio
tips = sns.load_dataset('tips')
fig, axes = plt.subplots(2, 2, figsize=(14, 12))
# 1. Violin plot — distribuzione per categoria
sns.violinplot(
data=tips, x='day', y='total_bill',
hue='sex', split=True, inner='quart',
palette='Set2', ax=axes[0, 0]
)
axes[0, 0].set_title('Violin Plot: Conto per Giorno e Sesso')
# 2. Swarm plot — punti individuali
sns.swarmplot(
data=tips, x='day', y='tip',
hue='smoker', dodge=True,
palette='coolwarm', size=5, ax=axes[0, 1]
)
axes[0, 1].set_title('Swarm Plot: Mance per Giorno')
# 3. Regression plot — relazione lineare
sns.regplot(
data=tips, x='total_bill', y='tip',
scatter_kws={'alpha': 0.5}, line_kws={'color': 'red'},
ax=axes[1, 0]
)
axes[1, 0].set_title('Regression Plot: Conto vs Mancia')
# 4. KDE plot — densità bivariata
sns.kdeplot(
data=tips, x='total_bill', y='tip',
fill=True, cmap='Blues', levels=15,
ax=axes[1, 1]
)
axes[1, 1].set_title('KDE Plot: Densità Bivariata')
plt.suptitle('Analisi Esplorativa con Seaborn', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.show()
2.3 Heatmap delle Correlazioni
Una delle visualizzazioni più richieste in assoluto nell'analisi dati è la matrice di correlazione. E Seaborn la rende davvero elegante (con pochissimo sforzo):
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# Creare un dataset simulato
np.random.seed(42)
n = 500
df = pd.DataFrame({
'Età': np.random.randint(18, 65, n),
'Reddito': np.random.normal(35000, 12000, n),
'Spesa_Mensile': np.random.normal(2000, 800, n),
'Ore_Lavoro': np.random.normal(40, 8, n),
'Soddisfazione': np.random.randint(1, 11, n),
'Anni_Esperienza': np.random.randint(0, 30, n)
})
df['Reddito'] = df['Reddito'] + df['Anni_Esperienza'] * 1500
df['Spesa_Mensile'] = df['Spesa_Mensile'] + df['Reddito'] * 0.03
# Calcolare la matrice di correlazione
corr = df.corr()
# Maschera per il triangolo superiore
mask = np.triu(np.ones_like(corr, dtype=bool))
fig, ax = plt.subplots(figsize=(10, 8))
sns.heatmap(
corr, mask=mask, annot=True, fmt='.2f',
cmap='RdBu_r', center=0,
square=True, linewidths=1,
cbar_kws={'shrink': 0.8, 'label': 'Coefficiente di Correlazione'},
ax=ax
)
ax.set_title('Matrice di Correlazione del Dataset', fontsize=14, pad=20)
plt.tight_layout()
plt.show()
2.4 Pair Plot e FacetGrid per Analisi Multi-Dimensionale
Per esplorare le relazioni tra più variabili contemporaneamente, pairplot e FacetGrid sono strumenti potentissimi. Il pair plot in particolare è spesso la prima cosa che faccio quando apro un nuovo dataset — dà una visione d'insieme immediata:
import seaborn as sns
import matplotlib.pyplot as plt
iris = sns.load_dataset('iris')
# Pair plot con istogrammi KDE sulla diagonale
g = sns.pairplot(
iris, hue='species',
diag_kind='kde',
plot_kws={'alpha': 0.6, 's': 50},
palette='viridis'
)
g.fig.suptitle('Pair Plot del Dataset Iris', y=1.02, fontsize=16)
plt.show()
# FacetGrid per analisi condizionata
tips = sns.load_dataset('tips')
g = sns.FacetGrid(tips, col='time', row='smoker', hue='sex', height=4)
g.map_dataframe(sns.scatterplot, x='total_bill', y='tip', alpha=0.7)
g.add_legend()
g.fig.suptitle('FacetGrid: Mance per Momento, Fumatore e Sesso', y=1.02)
plt.show()
3. Plotly: Interattività per il Web e Oltre
Ok, se Matplotlib e Seaborn dominano nella visualizzazione statica, Plotly è senza dubbio il re dell'interattività. I grafici Plotly sono nativamente interattivi: zoom, pan, tooltip e selezione funzionano out of the box, e possono essere integrati direttamente in applicazioni web e notebook Jupyter.
La prima volta che ho mostrato un grafico Plotly a un collega non tecnico, la reazione è stata: "Ah, ma posso cliccarci sopra!" — ed è esattamente questo il punto.
3.1 Installazione e Plotly Express
pip install plotly
Plotly Express è l'interfaccia di alto livello di Plotly, progettata per creare grafici complessi con una singola riga di codice:
import plotly.express as px
import pandas as pd
import numpy as np
# Creare un dataset simulato di vendite
np.random.seed(42)
mesi = pd.date_range('2024-01', periods=24, freq='ME')
regioni = ['Nord', 'Centro', 'Sud']
records = []
for regione in regioni:
base = {'Nord': 50000, 'Centro': 40000, 'Sud': 30000}[regione]
for mese in mesi:
vendite = base + np.random.normal(0, 5000) + mese.month * 1000
records.append({'Mese': mese, 'Regione': regione, 'Vendite': vendite})
df = pd.DataFrame(records)
# Grafico a linee interattivo
fig = px.line(
df, x='Mese', y='Vendite', color='Regione',
title='Andamento delle Vendite per Regione (2024-2025)',
labels={'Vendite': 'Vendite (€)', 'Mese': ''},
template='plotly_white'
)
fig.update_layout(
hovermode='x unified',
font=dict(size=13),
legend=dict(orientation='h', yanchor='bottom', y=1.02)
)
fig.show()
3.2 Grafici Avanzati con Plotly
Plotly si distingue per la capacità di creare visualizzazioni che sarebbero un incubo con le librerie statiche. Ecco un esempio di sunburst chart — perfetto per dati gerarchici:
import plotly.express as px
import pandas as pd
import numpy as np
# Sunburst chart — struttura gerarchica
dati_gerarchia = pd.DataFrame({
'Categoria': ['ML', 'ML', 'ML', 'Data Eng', 'Data Eng', 'Viz', 'Viz', 'Viz'],
'Sottocategoria': ['Supervisione', 'Non-Supervisione', 'Deep Learning',
'ETL', 'Streaming', 'Statica', 'Interattiva', 'Dashboard'],
'Valore': [40, 25, 35, 30, 20, 15, 25, 30]
})
fig = px.sunburst(
dati_gerarchia,
path=['Categoria', 'Sottocategoria'],
values='Valore',
title='Distribuzione delle Competenze Data Science',
color='Valore',
color_continuous_scale='RdBu'
)
fig.show()
E per chi vuole spingersi nel 3D, Plotly gestisce anche quello senza troppi problemi:
import plotly.graph_objects as go
import numpy as np
# Grafico 3D interattivo
theta = np.linspace(0, 4 * np.pi, 200)
z = np.linspace(-2, 2, 200)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
fig = go.Figure(data=[go.Scatter3d(
x=x, y=y, z=z,
mode='markers',
marker=dict(
size=4,
color=z,
colorscale='Viridis',
opacity=0.8,
colorbar=dict(title='Z')
)
)])
fig.update_layout(
title='Spirale 3D Interattiva',
scene=dict(
xaxis_title='X',
yaxis_title='Y',
zaxis_title='Z'
)
)
fig.show()
3.3 Mappe Geografiche con Plotly
Plotly include anche supporto nativo per visualizzazioni geospaziali. Nell'esempio qui sotto, usiamo un semplice grafico a barre orizzontali per confrontare le regioni italiane — ma il framework supporta anche mappe choropleth e scatter geo complete:
import plotly.express as px
import pandas as pd
# Dati delle regioni italiane (esempio semplificato)
regioni = pd.DataFrame({
'regione': ['Lombardia', 'Lazio', 'Campania', 'Sicilia', 'Veneto',
'Emilia-Romagna', 'Piemonte', 'Puglia', 'Toscana', 'Calabria'],
'popolazione_milioni': [10.0, 5.7, 5.6, 4.8, 4.9, 4.4, 4.3, 3.9, 3.7, 1.9],
'pil_pro_capite': [39000, 34000, 19000, 18000, 33000,
35000, 31000, 19000, 32000, 17000]
})
fig = px.bar(
regioni.sort_values('pil_pro_capite', ascending=True),
x='pil_pro_capite', y='regione',
orientation='h',
color='popolazione_milioni',
color_continuous_scale='Tealgrn',
title='PIL pro Capite per Regione Italiana',
labels={'pil_pro_capite': 'PIL pro Capite (€)', 'popolazione_milioni': 'Pop. (mln)'}
)
fig.update_layout(height=500)
fig.show()
4. Confronto Pratico: Quando Usare Quale Libreria
Questa è la domanda che mi fanno più spesso. La risposta dipende dal contesto, ma ecco una guida pratica:
- Report PDF o articoli scientifici → Matplotlib. Il controllo pixel-per-pixel e l'export in formati vettoriali (SVG, PDF) lo rendono imbattibile per le pubblicazioni.
- Analisi esplorativa rapida (EDA) → Seaborn. Poche righe di codice, grafici statistici informativi e ben formattati. Non serve altro.
- Presentazioni interattive e dashboard web → Plotly. L'interattività nativa e l'integrazione con Dash lo rendono perfetto per stakeholder non tecnici.
- Notebook Jupyter per condivisione → Plotly Express o Seaborn, a seconda che serva interattività o meno.
- Grafici 3D e animazioni web → Plotly. Il supporto nativo WebGL garantisce prestazioni elevate anche con grandi dataset.
Il mio consiglio? Non scegliete una sola libreria — imparatele tutte e tre e usate quella giusta per il contesto giusto.
5. Dashboard Interattivi: Da Grafici Singoli ad Applicazioni Complete
Creare un bel grafico è una cosa. Costruire un'intera dashboard interattiva è tutt'altra storia — ma è anche incredibilmente soddisfacente. Nel 2025-2026, tre framework dominano questo spazio: Dash, Streamlit e Panel.
5.1 Dashboard con Dash (Plotly)
Dash è il framework ufficiale di Plotly per creare applicazioni analitiche web. Si basa su Flask, React e Plotly.js — una combinazione potente che vi permette di andare dalla prototipazione alla produzione senza cambiare stack:
pip install dash
from dash import Dash, html, dcc, callback, Output, Input
import plotly.express as px
import pandas as pd
import numpy as np
# Generare dati di esempio
np.random.seed(42)
df = pd.DataFrame({
'mese': pd.date_range('2024-01', periods=12, freq='ME'),
'vendite': np.random.randint(10000, 50000, 12),
'costi': np.random.randint(5000, 30000, 12),
})
df['profitto'] = df['vendite'] - df['costi']
app = Dash(__name__)
app.layout = html.Div([
html.H1('Dashboard Vendite', style={'textAlign': 'center'}),
html.Div([
html.Label('Seleziona metrica:'),
dcc.Dropdown(
id='metrica-dropdown',
options=[
{'label': 'Vendite', 'value': 'vendite'},
{'label': 'Costi', 'value': 'costi'},
{'label': 'Profitto', 'value': 'profitto'}
],
value='vendite',
style={'width': '300px'}
),
], style={'padding': '20px'}),
dcc.Graph(id='grafico-principale')
])
@callback(
Output('grafico-principale', 'figure'),
Input('metrica-dropdown', 'value')
)
def aggiorna_grafico(metrica):
fig = px.bar(
df, x='mese', y=metrica,
title=f'Andamento {metrica.capitalize()} Mensile',
template='plotly_white',
color_discrete_sequence=['#1976D2']
)
fig.update_layout(
xaxis_title='',
yaxis_title=f'{metrica.capitalize()} (€)'
)
return fig
if __name__ == '__main__':
app.run(debug=True)
5.2 Dashboard con Streamlit
Se Dash è il framework "serio", Streamlit è quello che ti fa dire "wow, ho fatto una dashboard in 20 minuti". È ideale per prototipazione rapida e condivisione interna — niente callback, niente layout complicati, solo Python puro:
pip install streamlit
import streamlit as st
import pandas as pd
import numpy as np
import plotly.express as px
import matplotlib.pyplot as plt
import seaborn as sns
st.set_page_config(page_title='Dashboard Analisi Dati', layout='wide')
st.title('Dashboard di Analisi Dati')
# Sidebar per i filtri
st.sidebar.header('Configurazione')
n_campioni = st.sidebar.slider('Numero di campioni', 100, 5000, 1000)
distribuzione = st.sidebar.selectbox(
'Distribuzione',
['Normale', 'Esponenziale', 'Uniforme']
)
# Generare dati in base alla selezione
np.random.seed(42)
if distribuzione == 'Normale':
dati = np.random.normal(50, 15, n_campioni)
elif distribuzione == 'Esponenziale':
dati = np.random.exponential(10, n_campioni)
else:
dati = np.random.uniform(0, 100, n_campioni)
df = pd.DataFrame({'valori': dati})
# Layout a colonne
col1, col2, col3 = st.columns(3)
col1.metric('Media', f'{dati.mean():.2f}')
col2.metric('Deviazione Std', f'{dati.std():.2f}')
col3.metric('Mediana', f'{np.median(dati):.2f}')
# Grafici affiancati
col_a, col_b = st.columns(2)
with col_a:
st.subheader('Distribuzione (Plotly)')
fig = px.histogram(df, x='valori', nbins=40, template='plotly_white')
st.plotly_chart(fig, use_container_width=True)
with col_b:
st.subheader('Box Plot (Seaborn)')
fig_mpl, ax = plt.subplots(figsize=(8, 5))
sns.boxplot(data=df, y='valori', color='#42A5F5', ax=ax)
st.pyplot(fig_mpl)
Per avviare il dashboard, basta eseguire streamlit run nome_file.py dal terminale. Semplice, no?
6. Tecniche Avanzate di Visualizzazione
6.1 Animazioni con Matplotlib
Matplotlib supporta animazioni attraverso il modulo animation — utile per visualizzare come i dati evolvono nel tempo. Non è la cosa più intuitiva da configurare (lo ammetto), ma il risultato può essere davvero d'effetto:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
fig, ax = plt.subplots(figsize=(10, 6))
x = np.linspace(0, 2 * np.pi, 200)
linea, = ax.plot(x, np.sin(x), color='#1976D2', linewidth=2)
ax.set_ylim(-1.5, 1.5)
ax.set_title('Onda Sinusoidale Animata')
ax.grid(True, alpha=0.3)
def aggiorna(frame):
linea.set_ydata(np.sin(x + frame / 10))
return linea,
ani = animation.FuncAnimation(
fig, aggiorna, frames=200,
interval=30, blit=True
)
# Salvare come GIF o video
# ani.save('onda.gif', writer='pillow', fps=30)
plt.show()
6.2 Grafici Animati con Plotly
Plotly rende le animazioni decisamente più semplici, con il supporto integrato per frame e slider. Particolarmente utili per dati temporali — basta aggiungere animation_frame e il gioco è fatto:
import plotly.express as px
import pandas as pd
import numpy as np
# Simulare dati temporali per più categorie
np.random.seed(42)
anni = list(range(2015, 2026))
categorie = ['Python', 'R', 'Julia', 'Scala']
records = []
basi = {'Python': 60, 'R': 45, 'Julia': 10, 'Scala': 20}
for cat in categorie:
valore = basi[cat]
for anno in anni:
crescita = {'Python': 5, 'R': 1, 'Julia': 4, 'Scala': -0.5}[cat]
valore = valore + crescita + np.random.normal(0, 2)
records.append({
'Anno': anno,
'Linguaggio': cat,
'Popolarità': max(0, valore),
'Progetti': int(np.random.uniform(100, 1000))
})
df = pd.DataFrame(records)
fig = px.scatter(
df, x='Popolarità', y='Progetti',
animation_frame='Anno', animation_group='Linguaggio',
size='Progetti', color='Linguaggio',
hover_name='Linguaggio',
size_max=45,
range_x=[0, 120], range_y=[0, 1100],
title='Evoluzione della Popolarità dei Linguaggi di Data Science',
template='plotly_white'
)
fig.show()
6.3 Stile Professionale e Best Practices
Per creare visualizzazioni che non facciano pensare "l'ha fatto uno stagista con fretta" (scherzo... ma neanche troppo), è utile definire uno stile coerente per tutti i grafici di un progetto:
import matplotlib.pyplot as plt
import matplotlib as mpl
# Creare un foglio di stile personalizzato
stile_personalizzato = {
'figure.figsize': (12, 7),
'figure.dpi': 100,
'axes.titlesize': 16,
'axes.titleweight': 'bold',
'axes.labelsize': 13,
'axes.spines.top': False,
'axes.spines.right': False,
'font.family': 'sans-serif',
'font.size': 11,
'legend.fontsize': 11,
'legend.framealpha': 0.9,
'lines.linewidth': 2,
'xtick.labelsize': 11,
'ytick.labelsize': 11,
'grid.alpha': 0.3,
'grid.linestyle': '--',
}
# Applicare lo stile
plt.rcParams.update(stile_personalizzato)
# Ora tutti i grafici useranno queste impostazioni
fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4], [10, 20, 25, 30], label='Serie A')
ax.plot([1, 2, 3, 4], [15, 18, 22, 35], label='Serie B')
ax.set_title('Grafico con Stile Professionale')
ax.set_xlabel('Trimestre')
ax.set_ylabel('Valore (migliaia €)')
ax.legend()
ax.grid(True)
plt.show()
Ecco le best practices che consiglio di seguire sempre:
- Scegliere il tipo di grafico giusto: barre per confronti, linee per trend temporali, scatter per correlazioni, heatmap per matrici. Sembra banale, ma il grafico sbagliato può fuorviare completamente.
- Minimizzare il "chart junk": via i bordi inutili, gli sfondi pesanti, le decorazioni che non aggiungono informazione. Usate
axes.spinesper eliminare i bordi superiore e destro — il grafico respira subito meglio. - Usare palette accessibili: il ciclo
petroff10di Matplotlib 3.10 è progettato per essere accessibile ai daltonici. Seaborn offre la palettecolorblind. Non trascurate questo aspetto. - Annotare con parsimonia: aggiungete etichette solo dove servono per guidare l'interpretazione. Un grafico sovraccarico di testo non comunica, confonde.
- Mantenere coerenza: usate gli stessi colori per le stesse categorie in tutti i grafici di un report o dashboard. I vostri lettori vi ringrazieranno.
7. Integrazione con pandas: Dal DataFrame al Grafico
Una cosa che molti principianti non sanno è che pandas ha metodi di plotting integrati che si appoggiano a Matplotlib. Non servono per grafici complessi, ma per un'esplorazione veloce sono una scorciatoia comodissima:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Creare un dataset di vendite e-commerce
np.random.seed(42)
date = pd.date_range('2024-01-01', periods=365, freq='D')
df = pd.DataFrame({
'data': date,
'vendite': np.random.poisson(150, 365) + np.sin(np.arange(365) * 2 * np.pi / 365) * 50,
'visitatori': np.random.poisson(2000, 365),
'conversione': np.random.beta(2, 20, 365)
})
df.set_index('data', inplace=True)
# Media mobile a 30 giorni
df['vendite_ma30'] = df['vendite'].rolling(30).mean()
fig, axes = plt.subplots(3, 1, figsize=(14, 12), sharex=True)
# Vendite giornaliere con media mobile
df[['vendite', 'vendite_ma30']].plot(
ax=axes[0],
color=['#90CAF9', '#1565C0'],
alpha=[0.5, 1]
)
axes[0].set_title('Vendite Giornaliere con Media Mobile 30gg')
axes[0].set_ylabel('Vendite')
axes[0].legend(['Giornaliere', 'Media Mobile 30gg'])
# Visitatori
df['visitatori'].plot(ax=axes[1], color='#4CAF50', alpha=0.6)
axes[1].set_title('Visitatori Giornalieri')
axes[1].set_ylabel('Visitatori')
# Tasso di conversione
df['conversione'].plot(ax=axes[2], color='#FF9800', alpha=0.6)
axes[2].set_title('Tasso di Conversione')
axes[2].set_ylabel('Conversione (%)')
plt.suptitle('Dashboard E-Commerce 2024', fontsize=18, fontweight='bold')
plt.tight_layout()
plt.show()
8. Tendenze 2025-2026 nella Visualizzazione dei Dati
Il panorama della visualizzazione dati in Python si muove veloce. Ecco le tendenze che vale la pena tenere d'occhio:
- Dashboard interattivi al posto dei report statici: le organizzazioni vogliono sempre più dashboard in tempo reale che permettano a chiunque di esplorare i dati autonomamente. Dash, Streamlit e Panel stanno progressivamente sostituendo i classici report PDF.
- Accessibilità come priorità: il nuovo ciclo
petroff10di Matplotlib 3.10, sviluppato con modelli di visione cromatica e machine learning, riflette una tendenza crescente verso visualizzazioni universalmente accessibili. Era ora, sinceramente. - Data storytelling: i numeri da soli non convincono (e non hanno mai convinto, a dirla tutta). La capacità di costruire narrative visive con i dati è sempre più richiesta. Le visualizzazioni devono raccontare una storia, non solo mostrare dati grezzi.
- Supporto GPU e grandi dataset: con le librerie scientifiche che introducono supporto nativo per Array API e computazioni GPU, anche la visualizzazione si sta adattando. Plotly usa WebGL per gestire grafici con milioni di punti senza problemi di performance.
- Librerie dichiarative in crescita: Altair, basata su Vega-Lite, sta guadagnando popolarità per il suo approccio dichiarativo — descrivere cosa visualizzare anziché come farlo. Il codice risulta più conciso e leggibile.
- Combinazione di librerie: la tendenza è usare più librerie insieme, sfruttando i punti di forza di ciascuna. Seaborn per l'EDA, Matplotlib per la personalizzazione fine, Plotly per l'interattività. Il data scientist moderno deve saper navigare l'intero ecosistema.
Conclusione
La visualizzazione dei dati in Python nel 2025-2026 è più potente e accessibile che mai. Matplotlib resta la base solida e flessibile per ogni tipo di grafico personalizzato; Seaborn offre eleganza statistica con pochissimo codice; Plotly porta l'interattività nativa per dashboard e applicazioni web.
Il mio consiglio? Padroneggiare tutte e tre le librerie. Partite da Matplotlib per costruire una base solida, passate a Seaborn per l'analisi esplorativa rapida, e poi adottate Plotly e Dash per creare dashboard interattivi pronti per la produzione.
Con gli strumenti e le tecniche che abbiamo visto in questa guida, avete tutto il necessario per trasformare qualsiasi dataset in visualizzazioni chiare, informative e — perché no — anche belle da guardare. Il futuro della data visualization è interattivo, accessibile e narrativo: non si tratta più solo di mostrare numeri, ma di raccontare storie con i dati.