Größe des Pyplot-Streudiagramm-Markers

376

Im Pyplot-Dokument für das Streudiagramm:

matplotlib.pyplot.scatter(x, y, s=20, c='b', marker='o', cmap=None, norm=None,
                          vmin=None, vmax=None, alpha=None, linewidths=None,
                          faceted=True, verts=None, hold=None, **kwargs)

Die Markergröße

s: Größe in Punkten ^ 2. Es ist ein Skalar oder ein Array mit der gleichen Länge wie x und y.

Was für eine Einheit ist das points^2? Was bedeutet das? Bedeutet s=100das 10 pixel x 10 pixel?

Grundsätzlich versuche ich, Streudiagramme mit unterschiedlichen Markergrößen zu erstellen, und ich möchte herausfinden, was die sZahl bedeutet.

LWZ
quelle
ziemlich sicher, dass Punkte die gleichen Einheiten sind, die für Schriftarten verwendet werden.
Tacaswell
@tcaswell, meinst du, s=20die Markierungsgröße entspricht der eines fontsize=20Buchstabens?
LWZ
Nein, die Fläche beträgt 20 Punkte ^ 2, ein fontsize=20Buchstabe ist 20 Punkte hoch (oder was auch immer das Referenzzeichen in der Schrift ist, ist 20 Punkte groß).
Tacaswell
23
matplotlib.pyplot.plot()hat msparameter ( markersize) ein Äquivalent für matplotlib.pyplot.scatter()parameter s( size). Nur eine Erinnerung ..
Niekas
@neikas scheint mir, dass dies nicht der Fall ist, da einer in Pixel (Markierungsgröße) und der andere in dieser seltsamen Einheit mit quadratischen Punkten (Größe) angegeben ist. Das war für mich immer verwirrend, aber ich glaube, es hat damit zu tun, dass die Streudiagramm-Markergröße verwendet wird, um die Menge visuell proportional zu bezeichnen.
Heltonbiker

Antworten:

406

Dies kann eine etwas verwirrende Art der Definition der Größe sein, aber Sie geben im Grunde den Bereich des Markers an. Dies bedeutet, um die Breite (oder Höhe) des Markers zu verdoppeln, müssen Sie um den sFaktor 4 erhöhen. [Weil A = W H => (2W) (2H) = 4A]

Es gibt jedoch einen Grund, warum die Größe von Markern auf diese Weise definiert wird. Aufgrund der Skalierung der Fläche als Quadrat der Breite scheint das Verdoppeln der Breite die Größe tatsächlich um mehr als den Faktor 2 zu erhöhen (tatsächlich erhöht sie sie um den Faktor 4). Um dies zu sehen, betrachten Sie die folgenden zwei Beispiele und die Ausgabe, die sie erzeugen.

# doubling the width of markers
x = [0,2,4,6,8,10]
y = [0]*len(x)
s = [20*4**n for n in range(len(x))]
plt.scatter(x,y,s=s)
plt.show()

gibt

Geben Sie hier die Bildbeschreibung ein

Beachten Sie, wie schnell die Größe zunimmt. Wenn wir stattdessen haben

# doubling the area of markers
x = [0,2,4,6,8,10]
y = [0]*len(x)
s = [20*2**n for n in range(len(x))]
plt.scatter(x,y,s=s)
plt.show()

gibt

Geben Sie hier die Bildbeschreibung ein

Jetzt nimmt die scheinbare Größe der Marker auf intuitive Weise ungefähr linear zu.

Die genaue Bedeutung eines Punkts ist für Plotzwecke ziemlich willkürlich. Sie können einfach alle Größen nach einer Konstanten skalieren, bis sie vernünftig aussehen.

Hoffe das hilft!

Bearbeiten: (Als Antwort auf einen Kommentar von @Emma)

Es ist wahrscheinlich eine verwirrende Formulierung von meiner Seite. Die Frage nach der Verdoppelung der Breite eines Kreises, sodass im ersten Bild für jeden Kreis (wenn wir uns von links nach rechts bewegen) die Breite doppelt so groß ist wie die vorherige. Für den Bereich ist dies also ein Exponential mit Basis 4. Ähnlich das zweite Beispiel Jeder Kreis hat doppelte Fläche als die letzte, was ein Exponential mit der Basis 2 ergibt.

Es ist jedoch das zweite Beispiel (wo wir den Bereich skalieren), dass der Verdopplungsbereich den Kreis für das Auge doppelt so groß erscheinen lässt. Wenn also ein Kreis ngrößer erscheinen soll, vergrößern wir die Fläche um einen Faktor, nnicht um den Radius, sodass die scheinbare Größe linear mit der Fläche skaliert.

Bearbeiten , um den Kommentar von @TomaszGandor zu visualisieren:

So sieht es für verschiedene Funktionen der Markergröße aus:

Exponentielle, quadratische oder lineare Größe

x = [0,2,4,6,8,10,12,14,16,18]
s_exp = [20*2**n for n in range(len(x))]
s_square = [20*n**2 for n in range(len(x))]
s_linear = [20*n for n in range(len(x))]
plt.scatter(x,[1]*len(x),s=s_exp, label='$s=2^n$', lw=1)
plt.scatter(x,[0]*len(x),s=s_square, label='$s=n^2$')
plt.scatter(x,[-1]*len(x),s=s_linear, label='$s=n$')
plt.ylim(-1.5,1.5)
plt.legend(loc='center left', bbox_to_anchor=(1.1, 0.5), labelspacing=3)
plt.show()
Dan
quelle
2
Ich verstehe Ihren Standpunkt wahrscheinlich falsch, aber in Ihrem zweiten Beispiel erhöhen Sie s exponentiell (s = [20, 40, 80, 160, 320, 640]) und sagen, dass dies uns eine schöne linear aussehende Vergrößerung gibt. Wäre es nicht sinnvoller, wenn eine lineare Vergrößerung (z. B. s = [20, 40, 60, 80, 100, 120]) zu einem linear aussehenden Ergebnis führen würde?
Emma
@Emma Deine Intuition ist richtig, meinerseits ist der Wortlaut schlecht (alternativ schlechte Wahl der Skalierung der x-Achse). Ich habe in einer Bearbeitung mehr erklärt, weil es zu lang für einen Kommentar war.
Dan
1
Ist es möglich, den sWert entsprechend der Größe des Figurenfensters zu ändern ? Ich meine, wenn wir die Figurenfenster maximieren, hätte ich gerne größere Markierungen.
Sigur
2
Tolles Beispiel (nur das nötige Zeug!). Dies sollte nicht 4 ** nund sein 2 ** n, sondern n ** 4und n ** 2. Mit 2 ** ndem zweiten Diagramm wird nicht linear in Bezug auf den Kreisdurchmesser skaliert. Es geht immer noch zu schnell (nur nicht so viel übertrieben).
Tomasz Gandor
1
Um es kürzer auszudrücken - das zweite Diagramm zeigt die Quadratwurzel des Exponentials - das ist ein weiteres Exponential, nur etwas weniger steil.
Tomasz Gandor
218

Weil andere Antworten hier das behaupten s den Bereich des Markers bezeichnen, füge ich diese Antwort hinzu, um zu verdeutlichen, dass dies nicht unbedingt der Fall ist.

Größe in Punkten ^ 2

Das Argument sin plt.scatterbezeichnet die markersize**2. Wie die Dokumentation sagt

s: skalar oder array_like, Form (n,), optionale
Größe in Punkten ^ 2. Standard ist rcParams ['lines.markersize'] ** 2.

Dies kann wörtlich genommen werden. Um einen Marker zu erhalten, der x Punkte groß ist, müssen Sie diese Zahl quadrieren und dem sArgument geben.

Die Beziehung zwischen der Markierungsgröße eines Liniendiagramms und dem Streugrößenargument ist also das Quadrat. Um einen Streumarker mit der gleichen Größe wie einen Plotmarker mit einer Größe von 10 Punkten zu erzeugen, würden Sie daher aufrufen scatter( .., s=100).

Geben Sie hier die Bildbeschreibung ein

import matplotlib.pyplot as plt

fig,ax = plt.subplots()

ax.plot([0],[0], marker="o",  markersize=10)
ax.plot([0.07,0.93],[0,0],    linewidth=10)
ax.scatter([1],[0],           s=100)

ax.plot([0],[1], marker="o",  markersize=22)
ax.plot([0.14,0.86],[1,1],    linewidth=22)
ax.scatter([1],[1],           s=22**2)

plt.show()

Verbindung zu "Bereich"

Warum sprechen andere Antworten und sogar die Dokumentation von "Bereich", wenn es um den sParameter geht?

Natürlich sind die Punkteinheiten ** 2 Flächeneinheiten.

  • Für den Sonderfall eines quadratischen Markers ist marker="s"die Fläche des Markers tatsächlich direkt der Wert vons Parameters.
  • Für einen Kreis ist die Fläche des Kreises area = pi/4*s.
  • Bei anderen Markern besteht möglicherweise nicht einmal eine offensichtliche Beziehung zum Bereich des Markers.

Geben Sie hier die Bildbeschreibung ein

In allen Fällen ist die Fläche des Markers jedoch proportional zum sParameter . Dies ist die Motivation, es "Gebiet" zu nennen, obwohl es in den meisten Fällen nicht wirklich so ist.

Die Angabe der Größe der Streumarker in Bezug auf eine Menge, die proportional zur Fläche des Markers ist, ist insofern sinnvoll, als es die Fläche des Markers ist, die beim Vergleich verschiedener Flecken und nicht deren Seitenlänge oder Durchmesser wahrgenommen wird. Das Verdoppeln der zugrunde liegenden Menge sollte die Fläche des Markers verdoppeln.

Geben Sie hier die Bildbeschreibung ein

Was sind Punkte?

Bisher wird die Antwort auf die Bedeutung eines Streumarkers in Punkteinheiten angegeben. Punkte werden häufig in der Typografie verwendet, wobei Schriftarten in Punkten angegeben werden. Auch Linienbreiten werden häufig in Punkten angegeben. Die Standardgröße der Punkte in Matplotlib beträgt 72 Punkte pro Zoll (ppi) - 1 Punkt entspricht somit 1/72 Zoll.

Es kann nützlich sein, Größen anstelle von Punkten in Pixel angeben zu können. Wenn die Zahl dpi ebenfalls 72 ist, ist ein Punkt ein Pixel. Wenn die Zahl dpi unterschiedlich ist (Standard ist matplotlib fig.dpi=100),

1 point == fig.dpi/72. pixels

Während die Größe des Streumarkers in Punkten für unterschiedliche dpi-Zahlen unterschiedlich aussehen würde, könnte man einen 10 x 10 Pixel ^ 2-Marker erzeugen, bei dem immer die gleiche Anzahl von Pixeln abgedeckt wäre:

Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

import matplotlib.pyplot as plt

for dpi in [72,100,144]:

    fig,ax = plt.subplots(figsize=(1.5,2), dpi=dpi)
    ax.set_title("fig.dpi={}".format(dpi))

    ax.set_ylim(-3,3)
    ax.set_xlim(-2,2)

    ax.scatter([0],[1], s=10**2, 
               marker="s", linewidth=0, label="100 points^2")
    ax.scatter([1],[1], s=(10*72./fig.dpi)**2, 
               marker="s", linewidth=0, label="100 pixels^2")

    ax.legend(loc=8,framealpha=1, fontsize=8)

    fig.savefig("fig{}.png".format(dpi), bbox_inches="tight")

plt.show() 

Wenn Sie an einer Streuung in Dateneinheiten interessiert sind, überprüfen Sie diese Antwort .

Bedeutung von BeErnest
quelle
Fragen Sie sich, wie man berechnen würde, welchen Parameter man der Streuung geben soll, um einen Kreis zu erhalten, der den Durchmesser von beispielsweise 0,1 in reellen Koordinaten des Diagramms abdeckt (um die Lücke zwischen beispielsweise 0,4 und 0,5 in einem Diagramm von (0) zu füllen , 0) bis (1,1)?
Anatoly Alekseev
@AnatolyAlekseev Das sollte mit dieser Frage beantwortet werden .
ImportanceOfBeingErnest
21

Sie können Markierungsgröße verwenden , um die Größe des Kreises in der Plotmethode anzugeben

import numpy as np
import matplotlib.pyplot as plt

x1 = np.random.randn(20)
x2 = np.random.randn(20)
plt.figure(1)
# you can specify the marker size two ways directly:
plt.plot(x1, 'bo', markersize=20)  # blue circle with size 10 
plt.plot(x2, 'ro', ms=10,)  # ms is just an alias for markersize
plt.show()

Von hier aus

Geben Sie hier die Bildbeschreibung ein

zhaoqing
quelle
Die Frage betraf das Streudiagramm, und in matplotlib haben die beiden Darstellungsfunktionen unterschiedliche Parameter ( Markierungsgröße für die Darstellung und s für die Streuung ). Diese Antwort trifft also nicht zu.
Dom
3
@ Dom habe ich positiv bewertet, da diese Frage als erstes Ergebnis in Google angezeigt wird, selbst wenn ich nach "Pyplot Plot Marker Size" suche. Diese Antwort hilft also.
Przemek D
Ich weiß, dass die Plotmethode und die Streumethode in plt unterschiedlich sind, aber beide können das 'Streudiagramm' realisieren und die Markierungsgröße anpassen. Diese Antwort ist also nur eine weitere Lösung, wenn Sie die Plotmethode @Dom
zhaoqing
18

Es ist der Bereich des Markers. Ich meine, wenn Sie haben s1 = 1000und dann s2 = 4000ist die Beziehung zwischen dem Radius jedes Kreises : r_s2 = 2 * r_s1. Siehe folgendes Diagramm:

plt.scatter(2, 1, s=4000, c='r')
plt.scatter(2, 1, s=1000 ,c='b')
plt.scatter(2, 1, s=10, c='g')

Geben Sie hier die Bildbeschreibung ein

Ich hatte den gleichen Zweifel, als ich den Beitrag sah, also habe ich dieses Beispiel gemacht und dann ein Lineal auf dem Bildschirm verwendet, um die Radien zu messen.

Joaquin
quelle
Dies ist die sauberste und fettfreieste Antwort. Danke
Ayan Mitra
6

Ich habe auch versucht, "Scatter" zunächst für diesen Zweck zu verwenden. Nach einiger Zeitverschwendung habe ich mich für die folgende Lösung entschieden.

import matplotlib.pyplot as plt
input_list = [{'x':100,'y':200,'radius':50, 'color':(0.1,0.2,0.3)}]    
output_list = []   
for point in input_list:
    output_list.append(plt.Circle((point['x'], point['y']), point['radius'], color=point['color'], fill=False))
ax = plt.gca(aspect='equal')
ax.cla()
ax.set_xlim((0, 1000))
ax.set_ylim((0, 1000))
for circle in output_list:    
   ax.add_artist(circle)

Geben Sie hier die Bildbeschreibung ein

Dies basiert auf einer Antwort auf diese Frage

Ike
quelle
sehr hilfreich. Aber warum zwei Schleifen verwenden?
Grabantot
1
@grantantot kein Grund, nur nicht zu viel darüber nachgedacht.
Ike
2

Wenn die Größe der Kreise dem Quadrat des Parameters in entspricht s=parameter, weisen Sie jedem Element, das Sie an Ihr Größenarray anhängen, eine Quadratwurzel zu:s=[1, 1.414, 1.73, 2.0, 2.24] Wenn diese Werte verwendet und zurückgegeben werden, erhöht sich ihre relative Größe die Quadratwurzel der quadratischen Progression, die eine lineare Progression zurückgibt.

Wenn ich jedes Quadrat so platzieren würde, wie es in der Handlung ausgegeben wird : output=[1, 2, 3, 4, 5]. Versuchen Sie, die Liste zu interpretieren:s=[numpy.sqrt(i) for i in s]

user34028
quelle
1
Sollte i in outputnicht sein?
Sigur