taille du marqueur de nuage de points pyplot

376

Dans le document pyplot pour nuage de points:

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)

La taille du marqueur

s: taille en points ^ 2. Il s'agit d'un scalaire ou d'un tableau de la même longueur que x et y.

De quel type d'unité s'agit-il points^2? Qu'est-ce que ça veut dire? Ça s=100veut dire 10 pixel x 10 pixel?

Fondamentalement, j'essaie de faire des nuages ​​de points avec différentes tailles de marqueur, et je veux comprendre ce que signifie le snombre.

LWZ
la source
assez sûr que les points sont les mêmes unités utilisées pour les polices.
tacaswell
@tcaswell, vous voulez s=20dire que la taille du marqueur est égale à celle d'une fontsize=20lettre?
LWZ
non, la zone sera de 20 points ^ 2, une fontsize=20lettre mesure 20 pts (ou ce que le caractère de référence dans la police fait 20 pts).
tacaswell
24
matplotlib.pyplot.plot()a msparamètre ( markersize) un équivalent pour matplotlib.pyplot.scatter()paramètre s( size). Juste un rappel ..
niekas
@neikas il me semble qu'ils ne le sont pas, car l'un est en pixels (taille de marqueur) et l'autre est dans cette unité de points carrés étranges (taille). Cela a toujours été source de confusion pour moi, mais je pense que cela a à voir avec la taille du marqueur de nuage de points utilisée pour désigner la quantité de manière visuellement proportionnelle.
heltonbiker

Réponses:

406

Cela peut être une façon quelque peu déroutante de définir la taille, mais vous spécifiez essentiellement la zone du marqueur. Cela signifie que pour doubler la largeur (ou la hauteur) du marqueur, vous devez l'augmenter sd'un facteur 4. [car A = W H => (2W) (2H) = 4A]

Il y a cependant une raison pour laquelle la taille des marqueurs est définie de cette manière. En raison de la mise à l'échelle de l'aire en tant que carré de largeur, doubler la largeur semble en fait augmenter la taille de plus d'un facteur 2 (en fait, elle l'augmente d'un facteur 4). Pour voir cela, considérez les deux exemples suivants et la sortie qu'ils produisent.

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

donne

entrez la description de l'image ici

Remarquez comment la taille augmente très rapidement. Si au contraire nous avons

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

donne

entrez la description de l'image ici

Maintenant, la taille apparente des marqueurs augmente à peu près linéairement de manière intuitive.

Quant à la signification exacte de ce qu'est un «point», elle est assez arbitraire à des fins de traçage, vous pouvez simplement mettre à l'échelle toutes vos tailles par une constante jusqu'à ce qu'elles semblent raisonnables.

J'espère que cela t'aides!

Edit: (En réponse au commentaire de @Emma)

C'est probablement un libellé déroutant de ma part. La question demandait de doubler la largeur d'un cercle donc dans la première image pour chaque cercle (comme nous nous déplaçons de gauche à droite) sa largeur est le double du précédent donc pour la zone c'est une exponentielle avec la base 4. De même le deuxième exemple chaque cercle a une surface double du dernier ce qui donne une exponentielle avec la base 2.

Cependant, c'est le deuxième exemple (où nous mettons à l'échelle la zone) que la zone de doublement semble rendre le cercle deux fois plus grand à l'œil. Ainsi, si nous voulons qu'un cercle apparaisse comme un facteur nplus grand, nous augmenterions la zone d'un facteur et nnon le rayon, de sorte que la taille apparente évolue linéairement avec la zone.

Modifier pour visualiser le commentaire de @TomaszGandor:

Voici à quoi cela ressemble pour différentes fonctions de la taille du marqueur:

Taille exponentielle, carrée ou linéaire

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
la source
2
Je comprends probablement mal votre point, mais dans votre deuxième exemple, vous augmentez s de façon exponentielle (s = [20, 40, 80, 160, 320, 640]) et dites que cela nous donne une belle augmentation de taille à l'aspect linéaire. Ne serait-il pas plus logique que l'augmentation de la taille de façon linéaire (ex. S = [20, 40, 60, 80, 100, 120]) nous donne le résultat d'aspect linéaire?
Emma
@Emma Votre intuition est bonne, c'est une mauvaise formulation de ma part (alternativement mauvais choix de mise à l'échelle de l'axe x). J'en ai expliqué un peu plus dans un montage car c'était trop long pour un commentaire.
Dan
1
Est-il possible de changer la svaleur en fonction de la taille de la fenêtre de figure? Je veux dire, si nous maximisons les fenêtres des figures, j'aimerais avoir des marques de taille plus grandes.
Sigur
2
Excellent exemple (juste les trucs nécessaires!). Cela ne devrait pas être 4 ** net 2 ** n, mais n ** 4et n ** 2. Avec 2 ** nle deuxième tracé, l'échelle n'est pas linéaire en termes de diamètre de cercle. Il va encore trop vite (mais pas trop au-dessus).
Tomasz Gandor
1
Pour faire court - le deuxième graphique montre la racine carrée de l'exponentielle - qui est une autre exponentielle, juste un peu moins raide.
Tomasz Gandor
219

Parce que d'autres réponses ici prétendent que cela sdénote la zone du marqueur, j'ajoute cette réponse pour clarifier que ce n'est pas nécessairement le cas.

Taille en points ^ 2

L'argument sen plt.scatterindique le markersize**2. Comme le dit la documentation

s: scalaire ou array_like, forme (n,),
taille facultative en points ^ 2. La valeur par défaut est rcParams ['lines.markersize'] ** 2.

Cela peut être pris à la lettre. Pour obtenir un marqueur de x points, vous devez mettre ce nombre au carré et le donner à l' sargument.

Ainsi, la relation entre la taille de marqueur d'un tracé de ligne et l'argument de la taille de dispersion est le carré. Afin de produire un marqueur de dispersion de la même taille qu'un marqueur de tracé de taille 10 points, vous devez donc appeler scatter( .., s=100).

entrez la description de l'image ici

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

Connexion à "zone"

Alors pourquoi les autres réponses et même la documentation parlent de "zone" en ce qui concerne le sparamètre?

Bien sûr, les unités de points ** 2 sont des unités de surface.

  • Pour le cas particulier d'un marqueur carré marker="s", la surface du marqueur est en effet directement la valeur du sparamètre.
  • Pour un cercle, l'aire du cercle est area = pi/4*s.
  • Pour d'autres marqueurs, il peut même ne pas y avoir de relation évidente avec la zone du marqueur.

entrez la description de l'image ici

Dans tous les cas, cependant, l'aire du marqueur est proportionnelle au sparamètre . C'est la motivation pour l'appeler "zone" même si dans la plupart des cas ce n'est pas vraiment le cas.

Spécifier la taille des marqueurs de dispersion en termes d'une certaine quantité qui est proportionnelle à la zone du marqueur a du sens dans la mesure où c'est la zone du marqueur qui est perçue lors de la comparaison de différents patchs plutôt que de sa longueur ou de son diamètre latéral. C'est-à-dire que doubler la quantité sous-jacente devrait doubler la surface du marqueur.

entrez la description de l'image ici

Quels sont les points?

Jusqu'à présent, la réponse à ce que signifie la taille d'un marqueur de dispersion est donnée en unités de points. Les points sont souvent utilisés en typographie, où les polices sont spécifiées en points. Les largeurs de ligne sont également souvent spécifiées en points. La taille standard des points dans matplotlib est de 72 points par pouce (ppp) - 1 point est donc 1/72 pouces.

Il pourrait être utile de pouvoir spécifier des tailles en pixels au lieu de points. Si le chiffre dpi est également de 72, un point est un pixel. Si le chiffre dpi est différent (la valeur par défaut de matplotlib est fig.dpi=100),

1 point == fig.dpi/72. pixels

Alors que la taille du marqueur de dispersion en points serait donc différente pour différents ppp, on pourrait produire un marqueur de 10 x 10 pixels ^ 2, qui aurait toujours le même nombre de pixels couverts:

entrez la description de l'image ici entrez la description de l'image ici entrez la description de l'image ici

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

Si vous êtes intéressé par une dispersion dans les unités de données, cochez cette réponse .

ImportanceDeBestErnest
la source
Vous vous demandez comment calculer le paramètre s à donner à scatter pour obtenir un cercle qui couvre le diamètre de, disons, 0,1 en coordonnées réelles du tracé (de manière à combler l'écart entre, disons, 0,4 et 0,5 sur un tracé de (0 , 0) au (1,1)?
Anatoly Alekseev
@AnatolyAlekseev Cela devrait être répondu par cette question.
ImportanceOfBeingErnest
21

Vous pouvez utiliser markersize pour spécifier la taille du cercle dans la méthode de tracé

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

D' ici

entrez la description de l'image ici

zhaoqing
la source
La question portait sur le nuage de points et, dans matplotlib, les deux fonctions de tracé ont des paramètres différents ( taille de marqueur pour le tracé et s pour la dispersion ). Cette réponse ne s'applique donc pas.
Dom
3
@Dom J'ai voté positivement, car cette question apparaît comme le premier résultat dans google même lorsque je recherche "taille du marqueur de tracé pyplot", donc cette réponse aide.
Przemek D du
Je sais que la méthode de tracé et la méthode de dispersion sont différentes en plt, mais ils peuvent tous les deux réaliser le `` nuage de points '' et ajuster la taille du marqueur, donc cette réponse est juste une autre solution si vous utilisez la méthode de tracé @Dom
zhaoqing
18

C'est la zone du marqueur. Je veux dire si vous avez s1 = 1000puis s2 = 4000, la relation entre le rayon de chaque cercle est la suivante : r_s2 = 2 * r_s1. Voir l'intrigue suivante:

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

entrez la description de l'image ici

J'avais le même doute quand j'ai vu le message, alors j'ai fait cet exemple puis j'ai utilisé une règle sur l'écran pour mesurer les rayons.

Joaquin
la source
C'est la réponse la plus propre et la plus grasse. Merci
Ayan Mitra
6

J'ai également essayé d'utiliser «scatter» initialement à cette fin. Après pas mal de temps perdu - j'ai opté pour la solution suivante.

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)

entrez la description de l'image ici

Ceci est basé sur une réponse à cette question

Ike
la source
très utile. Mais pourquoi utiliser deux boucles?
grabantot
1
@grabantot aucune raison, n'y a pas trop réfléchi.
Ike
2

Si la taille des cercles correspond au carré du paramètre dans s=parameter, affectez une racine carrée à chaque élément que vous ajoutez à votre tableau de taille, comme ceci: de s=[1, 1.414, 1.73, 2.0, 2.24]telle sorte que lorsqu'il prend ces valeurs et les renvoie, leur augmentation de taille relative sera la racine carrée de la progression au carré, qui renvoie une progression linéaire.

Si je devais carré chacun comme il obtient la sortie de la parcelle: output=[1, 2, 3, 4, 5]. Essayez l'interprétation de la liste:s=[numpy.sqrt(i) for i in s]

user34028
la source
1
Devrait être i in outputne devrait pas?
Sigur