HOWTO · Matplotlib

Impostare la dimensione dei marker in un grafico a dispersione Matplotlib

Imposta una dimensione uguale o diversa per ogni marker con scatter, scala correttamente le aree e correggi un array di dimensioni non valido.

In questa pagina

Usa l’argomento s di Axes.scatter per impostare la dimensione dei marker in un grafico a dispersione Matplotlib. Uno scalare applica la stessa area nominale a ogni punto; una lista o un array unidimensionale assegna un’area a ciascun punto e deve avere la stessa lunghezza di x e y.

Impostare la dimensione dei marker con s

Passa l’argomento s ad Axes.scatter per impostare la dimensione del marker in un grafico a dispersione Matplotlib. Un valore scalare come s=80 assegna a tutti i punti la stessa area nominale. Un elenco o un array monodimensionale assegna invece un’area diversa a ciascun punto, ma deve contenere tanti valori quanti sono gli elementi di x e y. Per esempio, usa ax.scatter(x, y, s=80) per una dimensione unica oppure ax.scatter(x, y, s=[20, 40, 80, 160]) per quattro punti di dimensioni diverse.

Usa scatter quando la dimensione varia tra le osservazioni. Il metodo correlato plot usa markersize per una sola dimensione lineare del marker.

Usare una dimensione unica o una dimensione per punto

Questo esempio deterministico affianca una raccolta con dimensione scalare a una raccolta le cui dimensioni derivano dai dati. Gli stessi valori determinano anche il colore, mentre alpha rende più leggibili i marker sovrapposti. L’immagine salvata permette di controllare il risultato senza un backend interattivo.

import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]
y = [2, 3, 5, 7, 11]
values = [1, 2, 4, 7, 11]
sizes = [40 + value * 20 for value in values]

fig, (top, bottom) = plt.subplots(2, 1, figsize=(6, 7), layout="constrained")
uniform = top.scatter(x, y, s=80, color="tab:blue")
varying = bottom.scatter(x, y, s=sizes, c=values, cmap="viridis", alpha=0.75)

top.set(title="s = 80", xlabel="x", ylabel="y")
bottom.set(title="s = [60, 80, 120, 180, 260]", xlabel="x", ylabel="y")
fig.colorbar(varying, ax=bottom)

print("scalar sizes:", uniform.get_sizes().tolist())
print("per-point sizes:", varying.get_sizes().tolist())
fig.savefig("scatter-marker-sizes.webp", dpi=120)

I due oggetti PathCollection riportano esattamente i valori di s conservati da Matplotlib:

scalar sizes: [80]
per-point sizes: [60, 80, 120, 180, 260]

Due grafici a dispersione Matplotlib che confrontano un’area scalare unica con cinque aree diverse per punto.

La trasformazione parte da 40 e aggiunge 20 per ogni unità del dato: il valore più piccolo resta visibile e quello più grande non domina gli assi. Con dati reali, scegli e documenta un limite inferiore e superiore invece di passare direttamente valori grezzi estremi. Il colore può rappresentare la stessa variabile, come nell’esempio, oppure una variabile diversa; aggiungi una barra dei colori quando il colore esprime una quantità.

Capire i punti quadrati (pt²) e il valore predefinito

La documentazione di Matplotlib per scatter definisce s in punti quadrati (pt²), dove un punto tipografico equivale a 1/72 di pollice. Il valore predefinito è rcParams['lines.markersize'] ** 2. Di conseguenza, s è proporzionale all’area nominale del marker, ma s=100 non garantisce una forma visibile di esattamente 10 × 10 punti. Il tracciato del marker, i DPI della figura e lo stile del bordo incidono sul contorno finale.

L’effetto del bordo è più evidente sui marker piccoli. Quando linewidths è maggiore di zero ed edgecolors è visibile, il tratto è centrato sul limite del marker e ne aumenta l’estensione effettiva di metà dello spessore della linea. Usa linewidths=0 o edgecolors="none" per confrontare piccoli marker pieni senza alterarne la dimensione apparente con il bordo.

La dimensione del marker è misurata nello spazio di visualizzazione, non nelle unità dei dati degli assi x o y. Ingrandire il grafico o modificare i limiti degli assi non trasforma quindi il marker in un raggio espresso nelle coordinate dei dati.

Scalare correttamente area e larghezza lineare

Moltiplicare s per due raddoppia l’area nominale. Poiché l’estensione lineare cresce approssimativamente con la radice quadrata dell’area, moltiplicare s per quattro rende un marker della stessa forma largo circa il doppio. È una regola visiva proporzionale, non una garanzia geometrica esatta per ogni tracciato del marker.

import matplotlib.pyplot as plt

base = 36
area_sizes = [base, 2 * base, 4 * base]

fig, (top, bottom) = plt.subplots(2, 1, figsize=(6, 7), layout="constrained")
top.scatter([1, 2, 3], [1, 1, 1], s=area_sizes, linewidths=0)
top.set(title="s = [36, 72, 144]", yticks=[])
top.set_xticks([1, 2, 3], ["1", "2", "4"])

bottom.scatter([1], [1], s=10**2, linewidths=0)
(line,) = bottom.plot([2], [1], marker="o", linestyle="none", markersize=10,
                     color="tab:orange")
bottom.set(title="scatter: s = 10**2    plot: markersize = 10", xlim=(0.5, 2.5), yticks=[])

print("scatter areas:", area_sizes)
print("plot markersize:", line.get_markersize())
fig.savefig("scatter-size-scaling.webp", dpi=120)

I valori scelti e la dimensione del marker Line2D sono:

scatter areas: [36, 72, 144]
plot markersize: 10.0

Output Matplotlib che confronta i fattori dell’area di scatter e il parametro s di scatter con markersize di plot.

Scegliere scatter(s=...) o plot(markersize=...)

Usa scatter(s=...) per un grafico a dispersione, soprattutto quando ogni osservazione deve avere un’area o un colore proprio. Usa plot(marker="o", markersize=10) quando disegni un oggetto Line2D i cui nodi condividono la stessa dimensione del marker. Come indica la documentazione di Matplotlib per plot, markersize (o ms) è una dimensione lineare espressa in punti, non l’area in punti quadrati accettata da scatter.

Anche se scatter(s=10**2) e plot(markersize=10) esprimono dimensioni nominali correlate per i marker circolari, non presumere che il risultato sia identico al pixel. I marker delle raccolte e delle linee possono differire per tracciati normalizzati, bordi, backend di rendering e rasterizzazione.

Correggere un array di dimensioni non compatibile con i punti

Un valore s non scalare deve avere la stessa lunghezza dei punti da tracciare. Questo esempio intercetta il messaggio diagnostico della versione corrente di Matplotlib, così da mostrarlo senza un traceback completo:

import matplotlib.pyplot as plt

x = [1, 2, 3]
y = [1, 4, 9]

try:
    plt.scatter(x, y, s=[40, 80])
except ValueError as error:
    print(f"{type(error).__name__}: {error}")
else:
    raise AssertionError("a mismatched size array should fail")

Con Matplotlib 3.11.2, l’output è:

ValueError: s (size 2) cannot be broadcast to match x and y (size 3)

Le versioni meno recenti di Matplotlib possono formulare il ValueError in modo diverso, ma la correzione è la stessa: fornisci tre dimensioni per tre punti (x, y) oppure passa un’unica dimensione scalare.