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.


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

dá

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

dá

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

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 .


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


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.


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


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]


11
Deve ser i in outputnão deveria?
— Sigur
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.