HOWTO · Matplotlib
Markergröße in einem Matplotlib-Streudiagramm festlegen
Legen Sie mit Matplotlib scatter eine einheitliche oder punktweise Markergröße fest, skalieren Sie Markerflächen korrekt und beheben Sie unpassende Größenarrays.
Auf dieser Seite
Verwenden Sie das Argument s von Axes.scatter, um die Markergröße in einem Matplotlib-Streudiagramm festzulegen. Ein Skalar weist jedem Punkt dieselbe nominale Fläche zu; eine eindimensionale Liste oder ein Array weist jedem Punkt eine Fläche zu und muss so viele Werte wie x und y enthalten.
Markergröße mit s festlegen
Übergeben Sie das Argument s an Axes.scatter, um die Markergröße in einem Matplotlib-Streudiagramm festzulegen. Ein Skalar wie s=80 weist allen Punkten dieselbe nominelle Fläche zu. Eine eindimensionale Liste oder ein Array gibt jedem Punkt eine eigene Fläche, muss aber genauso viele Werte wie x und y enthalten. Verwenden Sie beispielsweise ax.scatter(x, y, s=80) für eine einheitliche Größe oder ax.scatter(x, y, s=[20, 40, 80, 160]) für vier unterschiedlich große Punkte.
Verwenden Sie scatter, wenn die Größen je Beobachtung variieren. Die verwandte Methode plot nutzt dagegen markersize für eine einzelne lineare Markerdimension.
Eine einheitliche oder punktweise Größe festlegen
Das folgende deterministische Beispiel stellt eine Sammlung mit skalarer Größe einer Sammlung gegenüber, deren Größen aus Daten berechnet werden. Dieselben Werte bestimmen außerdem die Farbe; alpha macht überlappende Marker leichter erkennbar. Das gespeicherte Bild zeigt das erwartete Ergebnis auch ohne interaktives Backend.
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)
Die beiden PathCollection-Objekte melden genau die s-Werte, die Matplotlib übernommen hat:
scalar sizes: [80]
per-point sizes: [60, 80, 120, 180, 260]
Die Transformation beginnt bei 40 und addiert für jede Dateneinheit 20. So bleibt selbst der kleinste Wert sichtbar, ohne dass der größte die Achsen dominiert. Wählen Sie bei realen Daten einen dokumentierten unteren und oberen Größenwert, statt extreme Rohwerte direkt zu übergeben. Die Farbe kann dieselbe oder eine andere Variable codieren; fügen Sie eine Farbskala hinzu, wenn Farben quantitative Werte darstellen.
Punkte zum Quadrat und den Standardwert verstehen
Die Matplotlib-scatter-Referenz definiert s in Punkten zum Quadrat (pt²), wobei ein typografischer Punkt 1/72 Zoll entspricht. Der Standardwert ist rcParams['lines.markersize'] ** 2. s ist somit proportional zur nominellen Markerfläche, doch s=100 garantiert keine tatsächlich sichtbare Form von 10 mal 10 Punkten. Markerpfad, Abbildungs-DPI und Kantenformatierung beeinflussen die endgültige Kontur.
Kanten wirken sich besonders auf kleine Marker aus. Ist linewidths größer als null und edgecolors sichtbar, liegt die Kontur mittig auf dem Markerrand und vergrößert die effektive Ausdehnung um die halbe Linienbreite. Verwenden Sie linewidths=0 oder edgecolors="none", wenn Sie kleine gefüllte Marker vergleichen und die Kante deren wahrgenommene Größe nicht verändern soll.
Die Markergröße ist eine Messung im Anzeigeraum und keine Einheit der x- oder y-Achse. Durch Zoomen oder geänderte Achsengrenzen wird ein Marker deshalb nicht zu einem Radius in Datenkoordinaten.
Markerfläche und lineare Breite korrekt skalieren
Wird s mit zwei multipliziert, verdoppelt sich die nominelle Fläche. Da die lineare Ausdehnung ungefähr mit der Quadratwurzel der Fläche wächst, macht eine Multiplikation von s mit vier einen ähnlich geformten Marker ungefähr doppelt so breit. Dies ist eine proportionale Darstellungsregel und keine exakte geometrische Garantie für jeden Markerpfad.
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)
Die gewählten Werte und die Markerdimension des Line2D-Objekts lauten:
scatter areas: [36, 72, 144]
plot markersize: 10.0
Zwischen scatter(s=...) und plot(markersize=...) wählen
Verwenden Sie scatter(s=...) für ein Streudiagramm, insbesondere wenn jede Beobachtung eine eigene Fläche oder Farbe benötigt. Nutzen Sie plot(marker="o", markersize=10) für ein Line2D-Objekt, dessen Punkte alle dieselbe Markergröße besitzen. Laut der Matplotlib-Referenz zu plot ist markersize (oder ms) eine lineare Größe in Punkten; sie entspricht nicht der von scatter erwarteten Fläche in Quadratpunkten.
Obwohl scatter(s=10**2) und plot(markersize=10) für kreisförmige Marker verwandte nominelle Abmessungen ausdrücken, sollten Sie sich nicht auf pixelgenaue Gleichheit verlassen. Marker in Sammlungen und Linien können sich wegen ihrer normalisierten Pfade, Kanten, Render-Backends und Rasterung unterscheiden.
Ein Größenarray mit falscher Länge korrigieren
Ein nicht skalares s muss genauso lang wie die gezeichneten Punkte sein. Dieses Beispiel fängt die aktuelle Matplotlib-Fehlermeldung ab, sodass sie ohne vollständigen Traceback angezeigt werden kann:
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")
Mit Matplotlib 3.11.2 lautet die Ausgabe:
ValueError: s (size 2) cannot be broadcast to match x and y (size 3)
Ältere Matplotlib-Versionen können den ValueError anders formulieren. Die Korrektur bleibt gleich: Übergeben Sie für drei (x, y)-Punkte drei Größenwerte oder einen einzelnen Skalar.