HOWTO · Matplotlib

Définir la taille des marqueurs d’un nuage de points Matplotlib

Définissez une taille unique ou une taille par point avec scatter de Matplotlib, dimensionnez correctement les aires et corrigez un tableau incompatible.

Sur cette page

Utilisez l’argument s de Axes.scatter pour définir la taille des marqueurs dans un nuage de points Matplotlib. Un scalaire applique la même aire nominale à chaque point, tandis qu’une liste ou un tableau unidimensionnel attribue une aire à chaque point et doit avoir la même longueur que x et y.

Définir la taille des marqueurs avec s

Transmettez l’argument s à Axes.scatter pour définir la taille des marqueurs dans un nuage de points Matplotlib. Un scalaire tel que s=80 attribue la même aire nominale à chaque point. Une liste ou un tableau unidimensionnel attribue une aire propre à chaque point, mais doit contenir autant de valeurs que x et y. Utilisez par exemple ax.scatter(x, y, s=80) pour une taille unique ou ax.scatter(x, y, s=[20, 40, 80, 160]) pour quatre points de tailles différentes.

Utilisez scatter lorsque la taille varie selon l’observation. La méthode apparentée plot emploie plutôt markersize pour une dimension linéaire unique du marqueur.

Définir une taille unique ou une taille par point

L’exemple déterministe suivant juxtapose une collection de taille scalaire et une collection dont les tailles sont calculées à partir des données. Les mêmes valeurs déterminent également la couleur et alpha rend les marqueurs superposés plus faciles à distinguer. L’image enregistrée permet de contrôler le résultat attendu sans backend interactif.

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)

Les deux objets PathCollection indiquent les valeurs exactes de s conservées par Matplotlib :

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

Deux nuages de points Matplotlib comparent une aire scalaire à cinq aires de marqueur propres aux points.

La transformation commence à 40 et ajoute 20 pour chaque unité de données. Même la plus petite valeur reste ainsi visible, sans que la plus grande domine les axes. Avec des données réelles, choisissez et documentez une plage de tailles minimale et maximale au lieu de transmettre directement des valeurs brutes extrêmes. La couleur peut coder la même variable, comme ci-dessus, ou une autre ; ajoutez une barre de couleurs lorsque celles-ci représentent une grandeur quantitative.

Comprendre les points carrés et la valeur par défaut

La documentation de scatter dans Matplotlib définit s en points carrés (pt²), un point typographique valant 1/72 de pouce. Sa valeur par défaut est rcParams['lines.markersize'] ** 2. Ainsi, s est proportionnel à l’aire nominale du marqueur, mais s=100 ne garantit pas une forme visible mesurant exactement 10 points sur 10. Le tracé du marqueur, les PPP de la figure et le style de la bordure influencent son contour final.

Les bordures influencent surtout les petits marqueurs. Lorsque linewidths est supérieur à zéro et qu’edgecolors est visible, le trait est centré sur la limite du marqueur et augmente son étendue effective de la moitié de l’épaisseur de ligne. Utilisez linewidths=0 ou edgecolors="none" pour comparer de petits marqueurs pleins sans que leur bordure ne modifie leur taille apparente.

La taille d’un marqueur est mesurée dans l’espace d’affichage, et non dans l’unité de données de l’axe x ou y. Zoomer ou modifier les limites des axes ne transforme donc pas le marqueur en rayon exprimé dans les coordonnées des données.

Dimensionner correctement l’aire et la largeur linéaire

Multiplier s par deux double l’aire nominale. Comme l’étendue linéaire croît approximativement avec la racine carrée de l’aire, multiplier s par quatre rend un marqueur de forme similaire environ deux fois plus large. Il s’agit d’une règle visuelle proportionnelle, et non d’une garantie géométrique exacte pour chaque tracé de marqueur.

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)

Les valeurs choisies et la dimension du marqueur Line2D sont les suivantes :

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

Résultat Matplotlib comparant des facteurs d’aire de scatter ainsi que l’argument s et markersize de plot.

Choisir scatter(s=...) ou plot(markersize=...)

Utilisez scatter(s=...) pour un nuage de points, notamment lorsque chaque observation doit avoir sa propre aire ou sa propre couleur. Utilisez plot(marker="o", markersize=10) pour tracer un objet Line2D dont les nœuds partagent tous la même taille de marqueur. Comme l’indique la documentation de plot dans Matplotlib, markersize (ou ms) est une taille linéaire en points et non l’aire en points carrés acceptée par scatter.

Même si scatter(s=10**2) et plot(markersize=10) expriment des dimensions nominales liées pour les marqueurs circulaires, ne comptez pas sur une égalité au pixel près. Les marqueurs de collections et de lignes peuvent différer en raison de leurs tracés normalisés, de leurs bordures, du backend de rendu et de la rastérisation.

Corriger un tableau de tailles qui ne correspond pas aux points

Une valeur s non scalaire doit avoir la même longueur que les points tracés. Cet exemple intercepte le diagnostic actuel de Matplotlib afin de l’afficher sans traceback complet :

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")

Avec Matplotlib 3.11.2, le résultat est :

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

Les versions antérieures de Matplotlib peuvent formuler le ValueError différemment, mais la correction reste la même : fournissez trois valeurs de taille pour trois points (x, y), ou transmettez une seule taille scalaire.