tamanho do marcador de plotagem de dispersão pyplot

376

No documento pyplot para plotagem de dispersão:

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)

O tamanho do marcador

s: tamanho em pontos ^ 2. É um escalar ou uma matriz do mesmo comprimento que x e y.

Que tipo de unidade é points^2? O que isso significa? Será que s=100quer dizer 10 pixel x 10 pixel?

Basicamente, estou tentando fazer gráficos de dispersão com tamanhos de marcador diferentes e quero descobrir o que esse snúmero significa.

LWZ
fonte
certeza de que os pontos são as mesmas unidades usadas para fontes.
214136 Tarauacá
@tcaswell, você quer dizer s=20significa que o tamanho do marcador é igual ao de uma fontsize=20letra?
LWZ
não, a área terá 20 pontos ^ 2, uma fontsize=20letra terá 20 pts de altura (ou o que o caractere de referência na fonte tiver 20 pts).
tacaswell
23
matplotlib.pyplot.plot()possui msparameter ( markersize) um equivalente para matplotlib.pyplot.scatter()parameter s( size). Apenas um lembrete ..
niekas
@neikas parece-me que não são, já que um está em pixels (tamanho do marcador) e outro nesta unidade de pontos quadrados estranhos (tamanho). Isso sempre foi confuso para mim, mas acredito que tenha a ver com o tamanho do marcador de gráfico de dispersão sendo usado para indicar a quantidade de maneira visualmente proporcional.
Heltonbiker # 26/17

Respostas:

406

Essa pode ser uma maneira um pouco confusa de definir o tamanho, mas você está basicamente especificando a área do marcador. Isso significa que, para dobrar a largura (ou altura) do marcador, é necessário aumentar sum fator de 4. [porque A = W H => (2W) (2H) = 4A]

Há uma razão, no entanto, que o tamanho dos marcadores é definido dessa maneira. Devido ao dimensionamento da área como o quadrado da largura, dobrar a largura na verdade parece aumentar o tamanho em mais de um fator 2 (na verdade, aumenta em um fator de 4). Para ver isso, considere os dois exemplos a seguir e a saída que eles produzem.

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

insira a descrição da imagem aqui

Observe como o tamanho aumenta muito rapidamente. Se, em vez disso, temos

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

insira a descrição da imagem aqui

Agora, o tamanho aparente dos marcadores aumenta aproximadamente linearmente de maneira intuitiva.

Quanto ao significado exato do que é um "ponto", é bastante arbitrário para fins de plotagem, você pode apenas dimensionar todos os seus tamanhos por uma constante até que pareçam razoáveis.

Espero que isto ajude!

Edit: (Em resposta ao comentário de @Emma)

Provavelmente é uma redação confusa da minha parte. A pergunta feita sobre dobrar a largura de um círculo, portanto, na primeira figura para cada círculo (à medida que avançamos da esquerda para a direita), sua largura é o dobro da anterior; portanto, para a área, é um exponencial com a base 4. Da mesma forma, o segundo exemplo cada círculo tem área duas vezes maior que a exponencial com base 2.

No entanto, é o segundo exemplo (onde estamos escalando a área) que a área duplicada parece fazer o círculo duas vezes maior do que o olho. Assim, se quisermos que um círculo apareça um fator nmaior, aumentaremos a área por um fator e nnão o raio, de modo que o tamanho aparente seja dimensionado linearmente com a área.

Edite para visualizar o comentário de @TomaszGandor:

É assim que parece para diferentes funções do tamanho do marcador:

Tamanho exponencial, quadrado ou linear

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
fonte
2
Provavelmente estou entendendo mal o seu ponto de vista, mas no seu segundo exemplo você está aumentando exponencialmente (s = [20, 40, 80, 160, 320, 640]) e dizendo que isso nos dá um bom aumento de tamanho de aparência linear. Não faria mais sentido se aumentar o tamanho linearmente (por exemplo, s = [20, 40, 60, 80, 100, 120]) nos desse o resultado de aparência linear?
Emma
@Emma Sua intuição está certa, é uma redação ruim da minha parte (em alternativa, má escolha da escala do eixo x). Expliquei um pouco mais em uma edição porque era muito longo para um comentário.
Dan
11
É possível alterar o svalor de acordo com o tamanho da janela da figura? Quero dizer, se maximizarmos as janelas de figuras, eu gostaria de ter marcas de tamanho maiores.
Sigur
2
Ótimo exemplo (apenas o material necessário!). Isso não deve ser 4 ** ne 2 ** n, mas n ** 4e n ** 2. Com 2 ** no segundo gráfico, não é dimensionado linearmente em termos de diâmetro do círculo. Ainda vai rápido demais (mas não muito por cima).
Tomasz Gandor
11
Para resumir - o segundo gráfico mostra a raiz quadrada do exponencial - que é outro exponencial, um pouco menos íngreme.
Tomasz Gandor
218

Como outras respostas aqui alegam que sdenota a área do marcador, estou adicionando esta resposta para esclarecer que esse não é necessariamente o caso.

Tamanho em pontos ^ 2

O argumento sem plt.scatterdenota o markersize**2. Como a documentação diz

s: escalar ou array_like, forma (n),
tamanho opcional nos pontos ^ 2. O padrão é rcParams ['lines.markersize'] ** 2.

Isso pode ser tomado literalmente. Para obter um marcador com x pontos grandes, você precisa quadrá-lo e apresentá-lo ao sargumento.

Portanto, a relação entre o tamanho do marcador de um gráfico de linha e o argumento do tamanho da dispersão é o quadrado. Para produzir um marcador de dispersão do mesmo tamanho que um marcador de plotagem de tamanho 10 pontos, você chamaria scatter( .., s=100).

insira a descrição da imagem aqui

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

Conexão com "área"

Então, por que outras respostas e até a documentação falam sobre "área" quando se trata do sparâmetro?

Obviamente, as unidades de pontos ** 2 são unidades de área.

  • Para o caso especial de um marcador quadrado marker="s", a área do marcador é de fato diretamente o valor do sparâmetro.
  • Para um círculo, a área do círculo é area = pi/4*s.
  • Para outros marcadores, pode até não haver nenhuma relação óbvia com a área do marcador.

insira a descrição da imagem aqui

Em todos os casos, porém, a área do marcador é proporcional ao sparâmetro . Essa é a motivação para chamá-la de "área", embora na maioria dos casos não seja realmente.

A especificação do tamanho dos marcadores de dispersão em termos de alguma quantidade proporcional à área do marcador faz sentido até agora, pois é a área do marcador que é percebida ao comparar diferentes amostras em vez de seu comprimento ou diâmetro lateral. Ou seja, dobrar a quantidade subjacente deve dobrar a área do marcador.

insira a descrição da imagem aqui

O que são pontos?

Até agora, a resposta para o significado do tamanho de um marcador de dispersão é dada em unidades de pontos. Os pontos são frequentemente usados ​​em tipografia, onde as fontes são especificadas em pontos. As larguras de linha também são frequentemente especificadas em pontos. O tamanho padrão dos pontos no matplotlib é 72 pontos por polegada (ppi) - 1 ponto é, portanto, 1/72 polegadas.

Pode ser útil poder especificar tamanhos em pixels em vez de pontos. Se a figura dpi também for 72, um ponto é um pixel. Se a figura dpi for diferente (o padrão matplotlib é fig.dpi=100),

1 point == fig.dpi/72. pixels

Embora o tamanho do marcador de dispersão em pontos pareça diferente para diferentes dpi de figura, pode-se produzir um marcador de 10 por 10 pixels ^ 2, que sempre terá o mesmo número de pixels cobertos:

insira a descrição da imagem aqui insira a descrição da imagem aqui insira a descrição da imagem aqui

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

Se você estiver interessado em uma dispersão nas unidades de dados, verifique esta resposta .

ImportanceOfBeingErnest
fonte
Pensando em como calcular o parâmetro a ser dado para espalhar para obter um círculo que cubra o diâmetro de, digamos, 0,1 em coordenadas reais do gráfico (para preencher a lacuna entre, digamos, 0,4 e 0,5 em um gráfico de (0 (0) a (1,1)?
Anatoly Alekseev
@AnatolyAlekseev Isso deve ser respondido por esta pergunta.
ImportanceOfBeingErnest
21

Você pode usar markersize para especificar o tamanho do círculo no método de plotagem

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

A partir daqui

insira a descrição da imagem aqui

zhaoqing
fonte
A questão era sobre gráfico de dispersão e, no matplotlib, as duas funções de plotagem têm parâmetros diferentes ( marcadores para plotagem e s para dispersão ). Portanto, esta resposta não se aplica.
Dom
3
@ Dom Eu votei, porque esta pergunta aparece como o primeiro resultado no google, mesmo quando eu pesquiso "tamanho do marcador de plotagem pyplot", então essa resposta ajuda.
Przemek D
Eu sei que o método de parcelas eo método de dispersão são diferentes em plt mas ambos podem realizar o 'gráfico de dispersão' e ajustar MarkerSize, assim que esta resposta é apenas mais um trabalho em torno de se você usar o método de parcelas @Dom
zhaoqing
18

É a área do marcador. Quero dizer, se você tem s1 = 1000e, em seguida s2 = 4000, a relação entre o raio de cada círculo é: r_s2 = 2 * r_s1. Veja o seguinte gráfico:

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

insira a descrição da imagem aqui

Eu tinha a mesma dúvida quando vi o post, então fiz este exemplo e usei uma régua na tela para medir os raios.

Joaquin
fonte
Esta é a resposta mais limpa e sem gordura. Obrigado
Ayan Mitra
6

Também tentei usar 'scatter' inicialmente para esse fim. Depois de muito tempo perdido - decidi pela seguinte solução.

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)

insira a descrição da imagem aqui

Isso é baseado em uma resposta a esta pergunta

Ike
fonte
Muito útil. Mas por que usar dois loops?
grabantot
11
@ Grabantot nenhuma razão, só não pensei muito nisso.
Ike
2

Se o tamanho dos círculos corresponder ao quadrado do parâmetro em s=parameter, atribua uma raiz quadrada a cada elemento que você anexa à sua matriz de tamanho, assim: de s=[1, 1.414, 1.73, 2.0, 2.24]modo que, quando ele pega esses valores e os retorna, seu aumento relativo de tamanho será a raiz quadrada da progressão ao quadrado, que retorna uma progressão linear.

Se eu fosse para quadrados cada um como ele fica de saída até ao terreno: output=[1, 2, 3, 4, 5]. Tente a interpretação da lista:s=[numpy.sqrt(i) for i in s]

user34028
fonte
11
Deve ser i in outputnão deveria?
Sigur