grootte markering van pyplot-spreidingsdiagram

In het pyplot-document voor scatterplot:

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)

De markeringsgrootte

en:
grootte in punten^2. Het is een scalair of een array van dezelfde lengte als x en y.

Wat voor soort eenheid is points^2? Wat betekent het? Betekent s=100 10 pixel x 10 pixel?

Eigenlijk probeer ik spreidingsdiagrammen te maken met verschillende markeringsgroottes, en ik wil uitzoeken wat het s-nummer betekent.


Antwoord 1, autoriteit 100%

Dit kan een enigszins verwarrende manier zijn om de grootte te definiëren, maar in feite specificeert u het gebied van de markering. Dit betekent dat om de breedte (of hoogte) van de markering te verdubbelen, je s met een factor 4 moet vergroten. [omdat A = WH => (2W)(2H)=4A]

Er is echter een reden dat de grootte van markeringen op deze manier wordt gedefinieerd. Vanwege de schaal van het gebied als het kwadraat van de breedte, lijkt een verdubbeling van de breedte de grootte met meer dan een factor 2 te vergroten (in feite wordt deze met een factor 4 vergroot). Bekijk de volgende twee voorbeelden en de output die ze produceren om dit te zien.

# 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()

geeft

voer hier de afbeeldingsbeschrijving in

Merk op hoe de maat zeer snel toeneemt. Als we in plaats daarvan

# 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()

geeft

voer hier de afbeeldingsbeschrijving in

Nu neemt de schijnbare grootte van de markeringen op een intuïtieve manier ongeveer lineair toe.

Wat betreft de exacte betekenis van wat een ‘punt’ is, het is vrij willekeurig voor plotdoeleinden, je kunt al je maten gewoon schalen met een constante totdat ze er redelijk uitzien.

Hopelijk helpt dit!

Bewerken: (In reactie op opmerking van @Emma)

Het is waarschijnlijk een verwarrende bewoording van mijn kant. De vraag over het verdubbelen van de breedte van een cirkel, dus in de eerste afbeelding voor elke cirkel (als we van links naar rechts bewegen) is de breedte het dubbele van de vorige, dus voor het gebied is dit een exponentiële met basis 4. Evenzo het tweede voorbeeld elke cirkel heeft een oppervlak het dubbele van de laatste, wat een exponentieel geeft met grondtal 2.

Het is echter het tweede voorbeeld (waar we het gebied schalen) dat verdubbelingsgebied de cirkel twee keer zo groot lijkt te maken voor het oog. Dus als we willen dat een cirkel een factor n groter lijkt, zouden we de oppervlakte met een factor n vergroten, niet de straal, dus de schijnbare grootte schaalt lineair met de oppervlakte.

Bewerken om de opmerking van @TomaszGandor te visualiseren:

Zo ziet het eruit voor verschillende functies van de markeringsgrootte:

Exponentiële, vierkante of lineaire grootte

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

Antwoord 2, autoriteit 54%

Omdat andere antwoorden hier beweren dat s het gebied van de markering aangeeft, voeg ik dit antwoord toe om duidelijk te maken dat dit niet noodzakelijk het geval is.

Grootte in punten^2

Het argument s in plt.scatter geeft de markersize**2 aan. Zoals de documentatie zegt

s : scalair of array_like, vorm (n, ), optioneel
grootte in punten^2. Standaard is rcParams[‘lines.markerssize’] ** 2.

Dit kan letterlijk worden genomen. Om een ​​markering te krijgen die x punten groot is, moet je dat getal kwadrateren en aan het argument s geven.

Dus de relatie tussen de markeringsgrootte van een lijnplot en het argument voor de spreidingsgrootte is het kwadraat. Om een ​​spreidingsmarkering te produceren van dezelfde grootte als een plotmarkering van 10 punten, roep je daarom scatter( .., s=100) aan.

voer hier de afbeeldingsbeschrijving in

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

Verbinding met “gebied”

Dus waarom spreken andere antwoorden en zelfs de documentatie over “gebied” als het gaat om de parameter s?

Natuurlijk zijn de eenheden van punten**2 oppervlakte-eenheden.

  • Voor het speciale geval van een vierkante markering, marker="s", is het gebied van de markering inderdaad direct de waarde van de parameter s.
  • Voor een cirkel is de oppervlakte van de cirkel area = pi/4*s.
  • Voor andere markeringen is er misschien niet eens een duidelijke relatie met het gebied van de markering.

voer hier de afbeeldingsbeschrijving in

In alle gevallen is het gebied van de markering echter evenredig met de s parameter. Dit is de motivatie om het “gebied” te noemen, hoewel dat in de meeste gevallen niet echt is.

Het specificeren van de grootte van de verstrooiingsmarkeringen in termen van een hoeveelheid die evenredig is met het gebied van de markering is in zoverre logisch, aangezien het het gebied van de markering is dat wordt waargenomen bij het vergelijken van verschillende patches in plaats van de lengte van de zijkant of diameter. D.w.z. verdubbeling van de onderliggende hoeveelheid zou de oppervlakte van de marker moeten verdubbelen.

voer hier de afbeeldingsbeschrijving in

Wat zijn punten?

Tot nu toe wordt het antwoord op wat de grootte van een spreidingsmarkering betekent, gegeven in eenheden van punten. Punten worden vaak gebruikt in typografie, waar lettertypen in punten worden gespecificeerd. Ook lijnbreedten worden vaak in punten aangegeven. De standaardgrootte van punten in matplotlib is 72 punten per inch (ppi) – 1 punt is dus 1/72 inch.

Het kan handig zijn om de grootte in pixels te kunnen specificeren in plaats van in punten. Als het cijfer dpi ook 72 is, is één punt één pixel. Als het cijfer dpi anders is (de standaardwaarde van matplotlib is fig.dpi=100),

1 point == fig.dpi/72. pixels

Hoewel de grootte van de spreidingsmarkering in punten er dus anders uitziet voor verschillende dpi-cijfers, zou men een markering van 10 bij 10 pixels^2 kunnen produceren, die altijd hetzelfde aantal pixels bedekt:

voer hier de afbeeldingsbeschrijving in
voer hier de afbeeldingsbeschrijving in
voer hier de afbeeldingsbeschrijving in

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

Als je geïnteresseerd bent in een spreiding in data-eenheden, bekijk dan dit antwoord.


Antwoord 3, autoriteit 6%

U kunt markersize gebruiken om de grootte van de cirkel in de plotmethode op te geven

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

Van hier

voer hier de afbeeldingsbeschrijving in


Antwoord 4, autoriteit 5%

Dit is het gebied van de markering. Ik bedoel, als je s1 = 1000 en dan s2 = 4000 hebt, is de relatie tussen de straal van elke cirkel: r_s2 = 2 * r_s1 . Zie de volgende plot:

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

voer hier de afbeeldingsbeschrijving in

Ik had dezelfde twijfel toen ik de post zag, dus ik deed dit voorbeeld en vervolgens gebruikte ik een liniaal op het scherm om de stralen te meten.


Antwoord 5, autoriteit 2%

Ik heb in eerste instantie ook geprobeerd om ‘scatter’ voor dit doel te gebruiken. Na nogal wat tijdverspilling – kwam ik tot de volgende oplossing.

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)

voer hier de afbeeldingsbeschrijving in

Dit is gebaseerd op een antwoord op deze vraag


Antwoord 6

Als de grootte van de cirkels overeenkomt met het kwadraat van de parameter in s=parameter, wijs dan een vierkantswortel toe aan elk element dat je toevoegt aan je groottearray, als volgt: s=[1, 1.414, 1.73, 2.0, 2.24] zodat wanneer deze waarden worden genomen en geretourneerd, hun relatieve groottetoename de vierkantswortel zal zijn van de kwadratische progressie, die een lineaire progressie retourneert.

Als ik ze allemaal zou kwadrateren als het wordt uitgevoerd naar de plot: output=[1, 2, 3, 4, 5]. Probeer lijstinterpretatie: s=[numpy.sqrt(i) for i in s]

LEAVE A REPLY

Please enter your comment!
Please enter your name here

20 + nine =

Other episodes