Grafici a Dispersione con Matplotlib in Python — Guida Completa
Impara a creare e personalizzare grafici a dispersione in Python con Matplotlib. Tratta colori, dimensioni, alpha, colorbar, gruppi multipli e annotazioni.
La funzione scatter() di Matplotlib ti consente di visualizzare la relazione tra due variabili numeriche posizionando un marcatore in ogni punto dati (x, y). A differenza di un grafico a linee, i grafici a dispersione non assumono nulla riguardo all'ordine o alla continuità — ogni punto è indipendente. Questo li rende la scelta ideale per esplorare correlazioni, individuare cluster e rilevare valori anomali.
Questo capitolo tratta tutto, dal primo grafico a dispersione alle tecniche professionali: codifica per punto di colore e dimensione, trasparenza, colorbar, grafici multi-gruppo, annotazioni dei punti e salvataggio di file pronti per la pubblicazione.
Prima di iniziare, assicurati che Matplotlib sia installato:
pip install matplotlibSe sei nuovo a Matplotlib, leggi prima i capitoli Introduzione a Matplotlib e Guida Introduttiva.
Quando Usare un Grafico a Dispersione
Usa un grafico a dispersione quando:
- Vuoi esplorare la correlazione tra due variabili numeriche (altezza vs. peso, ore di studio vs. punteggio all'esame).
- Hai bisogno di rilevare cluster — gruppi di punti che si raggruppano naturalmente.
- Vuoi identificare valori anomali — punti lontani dalla distribuzione principale.
- Stai codificando una terza variabile tramite la dimensione o il colore del marcatore (un "bubble chart" è un grafico a dispersione in cui la dimensione = una terza variabile).
Evita i grafici a dispersione quando un asse rappresenta categorie non ordinate — un grafico a barre è più chiaro in quel caso. Per tendenze su una variabile continua ordinata, un grafico a linee è più appropriato.
Creare un Grafico a Dispersione di Base
Passa due sequenze di uguale lunghezza — valori x e valori y — a plt.scatter():
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
y = [2, 4, 5, 4, 7, 8, 6, 9, 10, 12]
plt.scatter(x, y)
plt.title('Basic Scatter Plot')
plt.xlabel('X Values')
plt.ylabel('Y Values')
plt.tight_layout()
plt.show()plt.tight_layout() impedisce che le etichette vengano troncate — usalo prima di ogni chiamata a show() o savefig().
Personalizzare la Dimensione dei Marcatori
Il parametro s controlla la dimensione dei marcatori in punti quadrati (il valore predefinito è 20). Aumentalo per rendere i punti più visibili, specialmente nelle presentazioni:
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5, 6, 7, 8]
y = [3, 1, 4, 1, 5, 9, 2, 6]
plt.scatter(x, y, s=120)
plt.title('Larger Markers')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()
plt.show()Puoi anche passare una lista o array a s in modo che ogni punto abbia la propria dimensione — è così che si codifica una terza variabile numerica come dimensione delle bolle:
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [5, 3, 6, 2, 7]
sizes = [100, 300, 50, 400, 200] # third variable encoded as bubble area
plt.scatter(x, y, s=sizes)
plt.title('Bubble Chart — size encodes a third variable')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()
plt.show()Personalizzare il Colore dei Marcatori
Un Singolo Colore per Tutti i Punti
Passa qualsiasi nome di colore, stringa esadecimale o tupla RGB a c (o color):
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [2, 4, 1, 5, 3]
plt.scatter(x, y, s=100, c='steelblue')
plt.title('Single Color')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()
plt.show()Colore per Punto da una Variabile Numerica
Passare un array a c mappa ogni valore a un colore tramite la mappa cromatica specificata in cmap. Aggiungi plt.colorbar() per mostrare cosa rappresentano i colori:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(seed=42)
x = rng.random(50)
y = rng.random(50)
values = rng.random(50) # third variable, e.g. intensity or temperature
scatter = plt.scatter(x, y, s=80, c=values, cmap='viridis')
plt.colorbar(scatter, label='Intensity')
plt.title('Color-Mapped Scatter Plot')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()
plt.show()'viridis' è una mappa cromatica percettivamente uniforme, leggibile in scala di grigi e accessibile ai lettori daltonici. Altre buone scelte sono 'plasma', 'cividis' e 'coolwarm'.
Controllo della Trasparenza con alpha
Quando molti punti si sovrappongono, formano una massa opaca che nasconde la vera densità. Imposta alpha (0 = completamente trasparente, 1 = completamente opaco) per rivelare la struttura sovrapposta:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(seed=0)
x = rng.normal(loc=0, scale=1, size=300)
y = rng.normal(loc=0, scale=1, size=300)
plt.scatter(x, y, s=40, alpha=0.4)
plt.title('Transparent Markers Reveal Density (alpha=0.4)')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()
plt.show()Un buon punto di partenza è alpha=0.4 fino a 0.6. Regola in base al numero di punti.
Stilizzare i Bordi dei Marcatori
Usa edgecolors per aggiungere un bordo intorno a ogni marcatore e linewidths per controllare lo spessore del bordo. Questo aiuta i punti a risaltare su uno sfondo colorato:
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5, 6]
y = [3, 1, 4, 1, 5, 9]
plt.scatter(x, y, s=150, c='gold', edgecolors='black', linewidths=1.5)
plt.title('Markers with Edges')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()
plt.show()Passa edgecolors='none' per rimuovere completamente i bordi (questo è il valore predefinito per la maggior parte delle mappe cromatiche).
Tracciare Gruppi Multipli
Per confrontare i gruppi, chiama plt.scatter() una volta per gruppo e assegna un'etichetta. Matplotlib assegna automaticamente un colore diverso a ogni chiamata:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(seed=7)
# Group A — centered around (2, 3)
ax_x = rng.normal(loc=2, scale=0.5, size=30)
ax_y = rng.normal(loc=3, scale=0.5, size=30)
# Group B — centered around (5, 6)
bx_x = rng.normal(loc=5, scale=0.5, size=30)
bx_y = rng.normal(loc=6, scale=0.5, size=30)
# Group C — centered around (8, 2)
cx_x = rng.normal(loc=8, scale=0.5, size=30)
cx_y = rng.normal(loc=2, scale=0.5, size=30)
plt.scatter(ax_x, ax_y, s=60, label='Group A')
plt.scatter(bx_x, bx_y, s=60, label='Group B')
plt.scatter(cx_x, cx_y, s=60, label='Group C')
plt.legend()
plt.title('Multi-Group Scatter Plot')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()
plt.show()Ogni chiamata a scatter() sceglie automaticamente il colore successivo nel ciclo di colori predefinito. Passa c='red' (o qualsiasi colore) per sovrascrivere.
Annotare i Singoli Punti
Usa plt.annotate() per etichettare punti specifici — utile per evidenziare valori anomali o osservazioni chiave:
import matplotlib.pyplot as plt
cities = ['London', 'Berlin', 'Madrid', 'Rome', 'Paris']
population = [9.0, 3.7, 3.3, 2.8, 2.1] # millions
area = [1572, 892, 604, 1285, 105] # km²
plt.scatter(area, population, s=100, c='steelblue', edgecolors='black', linewidths=0.8)
for i, city in enumerate(cities):
plt.annotate(
city,
xy=(area[i], population[i]),
xytext=(8, 4), # offset in points
textcoords='offset points',
fontsize=9,
)
plt.title('European City Population vs. Area')
plt.xlabel('Area (km²)')
plt.ylabel('Population (millions)')
plt.tight_layout()
plt.show()Il pattern xytext + textcoords='offset points' sposta leggermente l'etichetta in modo che non si sovrapponga direttamente al marcatore.
Uso degli Assi Logaritmici
Quando i dati si estendono su diversi ordini di grandezza, gli assi lineari comprimono la maggior parte dei punti in un angolo. Passa a una scala logaritmica con plt.xscale('log') o plt.yscale('log'):
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(seed=1)
x = np.logspace(1, 5, 60) # 10¹ to 10⁵
y = x * rng.uniform(0.5, 2.0, 60) # roughly proportional, with noise
plt.scatter(x, y, s=40, alpha=0.7)
plt.xscale('log')
plt.yscale('log')
plt.title('Log-Scale Scatter Plot')
plt.xlabel('X (log scale)')
plt.ylabel('Y (log scale)')
plt.tight_layout()
plt.show()Entrambi gli assi coprono ora intervalli uniformi di potenze di dieci, distribuendo i dati in modo uniforme sull'area del grafico.
Aggiungere una Linea di Regressione
Un grafico a dispersione mostra i singoli punti; aggiungere una linea di miglior adattamento mostra la tendenza generale. Calcola pendenza e intercetta con np.polyfit():
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(seed=3)
x = np.linspace(0, 10, 40)
y = 2.5 * x + rng.normal(scale=3, size=40) # linear trend + noise
# Fit a degree-1 polynomial (straight line)
slope, intercept = np.polyfit(x, y, 1)
trend_line = slope * x + intercept
plt.scatter(x, y, s=50, label='Data points', alpha=0.7)
plt.plot(x, trend_line, color='red', linewidth=2, label=f'Trend (slope={slope:.2f})')
plt.legend()
plt.title('Scatter Plot with Regression Line')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()
plt.show()np.polyfit(x, y, 1) restituisce [slope, intercept] per la retta di miglior adattamento che passa per i punti.
Salvare un Grafico a Dispersione su File
Usa plt.savefig() invece di plt.show() per scrivere il grafico su disco. Chiamalo prima di plt.show() — dopo show() la figura viene cancellata:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(seed=9)
x = rng.random(60)
y = rng.random(60)
plt.scatter(x, y, s=60, alpha=0.6, c='teal', edgecolors='white', linewidths=0.5)
plt.title('Saved Scatter Plot')
plt.xlabel('X')
plt.ylabel('Y')
plt.tight_layout()
plt.savefig('scatter.png', dpi=150) # PNG at 150 DPI
plt.savefig('scatter.pdf') # vector PDF — best for publication
plt.show()Opzioni di formato comuni: 'png' (raster, web), 'pdf' (vettoriale, pubblicazione), 'svg' (vettoriale, web). Aumenta dpi a 300 per raster di qualità stampa.
scatter() vs plot() — Quale Usare?
Entrambe le funzioni possono tracciare grafici con soli marcatori, ma servono a scopi diversi:
| Funzionalità | plt.scatter() | plt.plot() |
|---|---|---|
Dimensione per punto (s) | Sì — passa un array | No |
Colore per punto (c) | Sì — passa un array | No (un colore per chiamata) |
| Supporto mappa cromatica | Sì (cmap) | Limitato |
| Prestazioni con grandi dataset | Più lento | Più veloce |
| Linea di collegamento | No | Sì |
Usa scatter() quando hai bisogno di stili per punto (il colore o la dimensione varia in base ai dati). Usa plot(marker='o', linestyle='None') per grafici a marcatori semplici su grandi dataset dove la velocità è importante. Consulta il capitolo Matplotlib Markers per ulteriori informazioni sugli stili dei marcatori.
Esempio Completo
Il seguente script autonomo combina le tecniche più utili — mappatura dei colori, codifica della dimensione, trasparenza, una colorbar e una legenda:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(seed=42)
n = 80
x = rng.standard_normal(n)
y = 0.8 * x + rng.standard_normal(n) * 0.6 # correlated
sizes = rng.uniform(30, 200, n) # bubble area
values = rng.random(n) # third variable for color
fig, ax = plt.subplots(figsize=(8, 5))
sc = ax.scatter(
x, y,
s=sizes,
c=values,
cmap='plasma',
alpha=0.75,
edgecolors='white',
linewidths=0.5,
)
plt.colorbar(sc, ax=ax, label='Intensity')
ax.set_title('Comprehensive Scatter Plot Example', fontsize=13)
ax.set_xlabel('X Variable')
ax.set_ylabel('Y Variable (correlated)')
fig.tight_layout()
plt.savefig('scatter_complete.png', dpi=150)
plt.show()Punti chiave:
fig, ax = plt.subplots()fornisce oggetti figura e assi espliciti — l'approccio consigliato per qualsiasi cosa oltre a un prototipo rapido.ax.scatter()su un oggettoAxessi comporta in modo identico aplt.scatter().plt.colorbar(sc, ax=ax, label='...')collega la colorbar agli assi specifici.
Best Practice
- Mostra la scala. Se usi
ccon una mappa cromatica, aggiungi sempre una colorbar in modo che i lettori sappiano cosa rappresentano i colori. - Evita il sovraffollamento. Per più di circa 500 punti, imposta
alpha < 1o passa a un istogramma 2D (plt.hist2d()) o a un grafico hexbin (plt.hexbin()). - Scegli mappe cromatiche accessibili.
'viridis','plasma'e'cividis'sono percettivamente uniformi e adatte ai daltonici. Evita'jet'e'rainbow'. - Etichetta gli assi con le unità.
plt.xlabel('Altezza (cm)')è più informativo diplt.xlabel('Altezza'). - Aggiungi un titolo che indichi il risultato. "Altezza vs. Peso — correlazione positiva" è più utile di "Grafico a Dispersione".
Capitoli Correlati
- Introduzione a Matplotlib — panoramica della libreria e installazione
- Guida Introduttiva a Matplotlib — le tue prime figure
- Grafici a Linee con Matplotlib — tendenze su variabili continue
- Grafici a Barre con Matplotlib — confronto tra categorie discrete
- Istogrammi con Matplotlib — distribuzione di una singola variabile
- Matplotlib Markers — ogni stile di marcatore e opzione di personalizzazione
- Sottotrame con Matplotlib — combinare più grafici in una singola figura