tamaño del marcador del diagrama de dispersión de las parcelas

376

En el documento de pyplot para el diagrama de dispersión:

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)

El tamaño del marcador

s: tamaño en puntos ^ 2. Es un escalar o una matriz de la misma longitud que x e y.

¿Qué tipo de unidad es points^2? Qué significa eso? ¿ s=100Significa 10 pixel x 10 pixel?

Básicamente, estoy tratando de hacer diagramas de dispersión con diferentes tamaños de marcador, y quiero averiguar qué significa el snúmero.

LWZ
fuente
Estoy bastante seguro de que los puntos son las mismas unidades utilizadas para las fuentes.
tacaswell
@tcaswell, ¿quiere s=20decir que el tamaño del marcador es igual al de una fontsize=20letra?
LWZ
no, el área será de 20 puntos ^ 2, una fontsize=20letra tendrá 20 pts de alto (o el carácter de referencia en la fuente tendrá 20 pts de alto).
tacaswell
23
matplotlib.pyplot.plot()tiene msparámetro ( markersize) un equivalente para matplotlib.pyplot.scatter()parámetro s( size). Solo un recordatorio ..
niekas
@neikas me parece que no lo son, ya que uno está en píxeles (tamaño de marcador) y el otro está en esta unidad de puntos cuadrados extraños (tamaño). Esto siempre ha sido confuso para mí, pero creo que tiene que ver con el tamaño del marcador de diagrama de dispersión que se utiliza para denotar la cantidad de una manera visualmente proporcional.
heltonbiker

Respuestas:

406

Esta puede ser una forma algo confusa de definir el tamaño, pero básicamente está especificando el área del marcador. Esto significa que, para duplicar el ancho (o altura) del marcador, debe aumentar sen un factor de 4. [porque A = W H => (2W) (2H) = 4A]

Sin embargo, hay una razón por la cual el tamaño de los marcadores se define de esta manera. Debido a la escala del área como el cuadrado del ancho, duplicar el ancho en realidad parece aumentar el tamaño en más de un factor 2 (de hecho, lo aumenta en un factor de 4). Para ver esto, considere los siguientes dos ejemplos y el resultado que producen.

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

da

ingrese la descripción de la imagen aquí

Observe cómo el tamaño aumenta muy rápidamente. Si en cambio tenemos

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

da

ingrese la descripción de la imagen aquí

Ahora, el tamaño aparente de los marcadores aumenta aproximadamente linealmente de manera intuitiva.

En cuanto al significado exacto de lo que es un "punto", es bastante arbitrario para propósitos de trazado, puede escalar todos sus tamaños por una constante hasta que parezcan razonables.

¡Espero que esto ayude!

Editar: (en respuesta al comentario de @Emma)

Probablemente sea una redacción confusa de mi parte. La pregunta fue sobre duplicar el ancho de un círculo, por lo que en la primera imagen para cada círculo (a medida que nos movemos de izquierda a derecha) su ancho es el doble del anterior, por lo que para el área es exponencial con la base 4. De manera similar, el segundo ejemplo cada círculo tiene un área doble al último, lo que da un exponencial con base 2.

Sin embargo, es el segundo ejemplo (donde estamos escalando el área) que el área de duplicación parece hacer que el círculo sea dos veces más grande a la vista. Por lo tanto, si queremos que un círculo parezca un factor nmayor, aumentaríamos el área en un factor que nno sea el radio, de modo que el tamaño aparente se escala linealmente con el área.

Edite para visualizar el comentario de @TomaszGandor:

Esto es lo que parece para diferentes funciones del tamaño del marcador:

Tamaño exponencial, cuadrado o lineal

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
fuente
2
Probablemente estoy malinterpretando su punto, pero en su segundo ejemplo está aumentando s exponencialmente (s = [20, 40, 80, 160, 320, 640]) y dice que eso nos da un buen aumento de tamaño de aspecto lineal. ¿No tendría más sentido si aumentar el tamaño linealmente (ej. S = [20, 40, 60, 80, 100, 120]) nos dio el resultado de aspecto lineal?
Emma
@Emma Tu intuición es correcta, es una mala redacción de mi parte (alternativamente, una mala elección de la escala del eje x). Le expliqué algo más en una edición porque era demasiado largo para un comentario.
Dan
1
¿Es posible cambiar el svalor de acuerdo con el tamaño de la ventana de la figura? Quiero decir, si maximizamos las ventanas de la figura, me gustaría tener marcas de mayor tamaño.
Sigur
2
Gran ejemplo (¡solo las cosas necesarias!). Esto no debería ser 4 ** ny 2 ** n, pero n ** 4y n ** 2. Con 2 ** nel segundo gráfico no se escala linealmente en términos de diámetro del círculo. Todavía va demasiado rápido (pero no demasiado por encima).
Tomasz Gandor
1
Para abreviar, la segunda gráfica muestra la raíz cuadrada de exponencial, que es otra exponencial, solo un poco menos pronunciada.
Tomasz Gandor
218

Debido a que otras respuestas aquí afirman que sdenota el área del marcador, estoy agregando esta respuesta para aclarar que este no es necesariamente el caso.

Tamaño en puntos ^ 2

El argumento sen plt.scatterdenota el markersize**2. Como dice la documentación

s: escalar o array_like, forma (n,),
tamaño opcional en puntos ^ 2. El valor predeterminado es rcParams ['lines.markersize'] ** 2.

Esto se puede tomar literalmente. Para obtener un marcador que sea x puntos grandes, debe cuadrar ese número y asignarlo al sargumento.

Entonces, la relación entre el tamaño del marcador de un diagrama lineal y el argumento del tamaño de dispersión es el cuadrado. Para producir un marcador de dispersión del mismo tamaño que un marcador de trama de 10 puntos, debería llamar scatter( .., s=100).

ingrese la descripción de la imagen aquí

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

Conexión a "área"

Entonces, ¿por qué otras respuestas e incluso la documentación hablan sobre "área" cuando se trata del sparámetro?

Por supuesto, las unidades de puntos ** 2 son unidades de área.

  • Para el caso especial de un marcador cuadrado marker="s", el área del marcador es directamente el valor del sparámetro.
  • Para un círculo, el área del círculo es area = pi/4*s.
  • Para otros marcadores, puede que ni siquiera haya una relación obvia con el área del marcador.

ingrese la descripción de la imagen aquí

En todos los casos, sin embargo, el área del marcador es proporcional al sparámetro . Esta es la motivación para llamarlo "área", aunque en la mayoría de los casos no lo es realmente.

Especificar el tamaño de los marcadores de dispersión en términos de cierta cantidad que es proporcional al área del marcador tiene sentido, ya que es el área del marcador que se percibe al comparar diferentes parches en lugar de su longitud lateral o diámetro. Es decir, duplicar la cantidad subyacente debería duplicar el área del marcador.

ingrese la descripción de la imagen aquí

¿Qué son los puntos?

Hasta ahora, la respuesta a lo que significa el tamaño de un marcador de dispersión se da en unidades de puntos. Los puntos se usan a menudo en tipografía, donde las fuentes se especifican en puntos. También los anchos de línea a menudo se especifican en puntos. El tamaño estándar de los puntos en matplotlib es 72 puntos por pulgada (ppi); por lo tanto, 1 punto es 1/72 pulgadas.

Puede ser útil poder especificar tamaños en píxeles en lugar de puntos. Si la cifra de dpi también es 72, un punto es un píxel. Si la cifra de dpi es diferente (el valor predeterminado de matplotlib es fig.dpi=100),

1 point == fig.dpi/72. pixels

Si bien el tamaño del marcador de dispersión en puntos se vería diferente para diferentes ppp de figura, se podría producir un marcador ^ 2 de 10 por 10 píxeles, que siempre tendría el mismo número de píxeles cubiertos:

ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

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 está interesado en una dispersión en unidades de datos, marque esta respuesta .

Importancia de ser ernesto
fuente
Preguntándose cómo se calcularía qué parámetro s dar a la dispersión para obtener un círculo que cubra el diámetro de, digamos, 0.1 en coordenadas reales de la gráfica (para llenar el espacio entre digamos 0.4 y 0.5 en una gráfica de (0 , 0) a (1,1)?
Anatoly Alekseev
@AnatolyAlekseev Eso debería responderse con esta pregunta.
ImportanceOfBeingErnest
21

Puede usar markersize para especificar el tamaño del círculo en el método de trazado

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

Desde aqui

ingrese la descripción de la imagen aquí

zhaoqing
fuente
La pregunta era sobre el diagrama de dispersión, y en matplotlib las dos funciones de trazado tienen parámetros diferentes ( marcador de tamaño para el diagrama y s para dispersión ). Entonces esta respuesta no aplica.
Dom
3
@Dom he votado, porque esta pregunta aparece como el primer resultado en google incluso cuando busco "tamaño de marcador de diagrama de pyplot", por lo que esta respuesta ayuda.
Przemek D
Sé que el método de trazado y el método de dispersión son diferentes en plt, pero ambos pueden realizar el 'diagrama de dispersión' y ajustar el tamaño del marcador, por lo que esta respuesta es solo otra solución si usa el método de trazado @Dom
zhaoqing
18

Es el área del marcador. Es decir, si usted tiene s1 = 1000y luego s2 = 4000, la relación entre el radio de cada círculo es: r_s2 = 2 * r_s1. Ver la siguiente trama:

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

ingrese la descripción de la imagen aquí

Tuve la misma duda cuando vi la publicación, así que hice este ejemplo y luego usé una regla en la pantalla para medir los radios.

Joaquin
fuente
Esta es la respuesta más limpia y libre de grasa. Gracias
Ayan Mitra
6

También intenté usar 'dispersión' inicialmente para este propósito. Después de perder un poco de tiempo, me decidí por la siguiente solución.

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)

ingrese la descripción de la imagen aquí

Esto se basa en una respuesta a esta pregunta

Ike
fuente
muy útil. Pero, ¿por qué usar dos bucles?
grabantot
1
@grabantot no hay razón, simplemente no pensé demasiado en ello.
Ike
2

Si el tamaño de los círculos corresponde al cuadrado del parámetro en s=parameter, entonces asigne una raíz cuadrada a cada elemento que agregue a su matriz de tamaño, de esta manera: de s=[1, 1.414, 1.73, 2.0, 2.24]modo que cuando tome estos valores y los devuelva, su aumento de tamaño relativo será La raíz cuadrada de la progresión al cuadrado, que devuelve una progresión lineal.

Si tuviera que al cuadrado cada uno como se pone de salida a la parcela: output=[1, 2, 3, 4, 5]. Prueba la interpretación de la lista:s=[numpy.sqrt(i) for i in s]

usuario34028
fuente
1
¿Debería ser i in outputno debería?
Sigur