Eu tenho um conjunto de pontos de dados X, Y (cerca de 10k) que são fáceis de plotar como um gráfico de dispersão, mas que eu gostaria de representar como um mapa de calor.
Examinei os exemplos no MatPlotLib e todos parecem já começar com os valores das células do mapa de calor para gerar a imagem.
Existe um método que converte um monte de x, y, todos diferentes, em um mapa de calor (onde zonas com maior frequência de x, y seriam "mais quentes")?
python
matplotlib
heatmap
histogram2d
cinza
fonte
fonte
Respostas:
Se você não deseja hexágonos, pode usar a
histogram2d
função numpy :Isso cria um mapa de calor de 50x50. Se você quiser, digamos, 512x384, pode fazer
bins=(512, 384)
a chamada parahistogram2d
.Exemplo:
fonte
axes
instância normal , onde posso adicionar um título, rótulos de eixos etc. e, em seguida, fazer o normalsavefig()
como faria em qualquer outro gráfico matplotlib típico.plt.savefig('filename.png')
funciona? Se você deseja obter uma instância eixos, use interface orientada a objetos de Matplotlib:fig = plt.figure()
ax = fig.gca()
ax.imshow(...)
fig.savefig(...)
imshow()
está na mesma categoria de funções quescatter()
. Sinceramente, não entendo por queimshow()
converte uma matriz 2D de carros alegóricos em blocos de cores apropriadas, enquanto eu entendo o quescatter()
é suposto fazer com essa matriz.plt.imshow(heatmap.T, extent=extent, origin = 'lower')
from matplotlib.colors import LogNorm
plt.imshow(heatmap, norm=LogNorm())
plt.colorbar()
No léxico Matplotlib , acho que você quer uma plotagem hexbin .
Se você não estiver familiarizado com esse tipo de gráfico, é apenas um histograma bivariado no qual o plano xy é mosaico por uma grade regular de hexágonos.
Assim, a partir de um histograma, você pode apenas contar o número de pontos que caem em cada hexágono, discretizar a região de plotagem como um conjunto de janelas , atribuir cada ponto a uma dessas janelas; finalmente, mapeie as janelas em uma matriz de cores e você terá um diagrama hexbin.
Embora menos comumente usado do que, por exemplo, círculos ou quadrados, os hexágonos sejam a melhor opção para a geometria do recipiente de armazenamento é intuitivo:
hexágonos têm simetria do vizinho mais próximo (por exemplo, caixas quadradas não, por exemplo, a distância de um ponto na borda de um quadrado até um ponto dentro desse quadrado não é igual em todo lugar) e
hexágono é o polígono n mais alto que fornece mosaico plano regular (ou seja, você pode remodelar com segurança o piso da cozinha com ladrilhos em formato hexagonal, porque você não terá espaço vazio entre os ladrilhos quando terminar - não é verdade para todos os outros polígonos com n superior, n> = 7).
( Matplotlib usa o termo plotagem de hexbin ; assim como (AFAIK) todas as bibliotecas de plotagem para R ; ainda não sei se esse é o termo geralmente aceito para plotagens desse tipo, embora eu suspeite que seja provável, dado que a hexbin é curta para bin hexagonal , que descreve a etapa essencial na preparação dos dados para exibição.)
fonte
gridsize=
parâmetro. Eu gostaria de escolhê-lo assim, para que os hexágonos se toquem sem se sobrepor. Percebi quegridsize=100
isso produziria hexágonos menores, mas como escolher o valor adequado?Edit: Para uma melhor aproximação da resposta de Alejandro, veja abaixo.
Sei que essa é uma pergunta antiga, mas queria acrescentar algo ao analisador de Alejandro: Se você deseja uma boa imagem suavizada sem usar o py-sphviewer, pode usar
np.histogram2d
e aplicar um filtro gaussiano (descipy.ndimage.filters
) no mapa de calor:Produz:
O gráfico de dispersão es = 16 plotados em cima um do outro para Agape Gal'lo (clique para ver melhor):
Uma diferença que notei com minha abordagem de filtro gaussiano e a abordagem de Alejandro foi que o método dele mostra estruturas locais muito melhores que as minhas. Portanto, implementei um método vizinho mais próximo simples no nível de pixel. Este método calcula para cada pixel a soma inversa das distâncias dos
n
pontos mais próximos nos dados. Esse método está em uma alta resolução bastante caro em termos de computação e acho que há uma maneira mais rápida; então, deixe-me saber se você tem alguma melhoria.Atualização: Como eu suspeitava, existe um método muito mais rápido usando o Scipy's
scipy.cKDTree
. Vejo a resposta de Gabriel para a implementação.Enfim, aqui está o meu código:
Resultado:
fonte
myplot
função, adicionar orange
parâmetro denp.histogram2d
:np.histogram2d(x, y, bins=bins, range=[[-5, 5], [-3, 4]])
e na for-loop definir a x e y lim do eixo:ax.set_xlim([-5, 5])
ax.set_ylim([-3, 4])
. Além disso, por padrão,imshow
mantém a proporção idêntica à proporção dos seus eixos (portanto, no meu exemplo, uma proporção de 10: 7), mas se você deseja que ela corresponda à sua janela de plotagem, adicione o parâmetroaspect='auto'
aimshow
.Em vez de usar o np.hist2d, que geralmente produz histogramas bastante feios, eu gostaria de reciclar o py-sphviewer , um pacote python para renderizar simulações de partículas usando um kernel de suavização adaptável e que pode ser facilmente instalado a partir do pip (consulte a documentação da página da web). Considere o seguinte código, que é baseado no exemplo:
que produz a seguinte imagem:
Como você vê, as imagens parecem muito boas e somos capazes de identificar diferentes subestruturas nela. Essas imagens são construídas espalhando um determinado peso para cada ponto dentro de um determinado domínio, definido pelo comprimento de suavização, que por sua vez é dado pela distância do vizinho nb mais próximo (eu escolhi 16, 32 e 64 para os exemplos). Portanto, regiões de alta densidade geralmente estão espalhadas por regiões menores em comparação com regiões de menor densidade.
A função myplot é apenas uma função muito simples que eu escrevi para fornecer os dados x, y ao py-sphviewer para fazer a mágica.
fonte
Se você estiver usando o 1.2.x
fonte
O Seaborn agora tem a função de plotagem conjunta, que deve funcionar bem aqui:
fonte
fig = plt.figure(figsize=(12, 12))
, depois obtenha o eixo atual comax=plt.gca()
, depois adicione o argumentoax=ax
àjointplot
função.e a pergunta inicial era ... como converter valores de dispersão em valores de grade, certo?
histogram2d
conta a frequência por célula; no entanto, se você tiver outros dados por célula além da frequência, precisará de mais trabalho.Então, eu tenho um conjunto de dados com resultados Z para as coordenadas X e Y. No entanto, eu estava calculando alguns pontos fora da área de interesse (grandes lacunas) e montes de pontos em uma pequena área de interesse.
Sim, aqui fica mais difícil, mas também mais divertido. Algumas bibliotecas (desculpe):
Hoje, o pyplot é meu mecanismo gráfico, cm é uma variedade de mapas de cores com algumas opções interessantes. numpy para os cálculos e dados de grade para anexar valores a uma grade fixa.
O último é importante, especialmente porque a frequência dos pontos xy não é igualmente distribuída nos meus dados. Primeiro, vamos começar com alguns limites adequados aos meus dados e um tamanho de grade arbitrário. Os dados originais possuem pontos de dados também fora desses limites x e y.
Portanto, definimos uma grade com 500 pixels entre os valores mínimo e máximo de x e y.
Nos meus dados, existem muito mais que os 500 valores disponíveis na área de alto interesse; considerando que na área de baixo interesse não existem nem 200 valores na grade total; entre os limites gráficos de
x_min
ex_max
há ainda menos.Portanto, para obter uma boa imagem, a tarefa é obter uma média dos altos valores de juros e preencher as lacunas em outros lugares.
Eu defino minha grade agora. Para cada par xx-yy, quero ter uma cor.
Por que a forma estranha? scipy.griddata quer uma forma de (n, D).
Griddata calcula um valor por ponto na grade, por um método predefinido. Eu escolhi "mais próximo" - pontos de grade vazios serão preenchidos com valores do vizinho mais próximo. Parece que as áreas com menos informações têm células maiores (mesmo que não seja o caso). Pode-se optar por interpolar "linear", então áreas com menos informações parecem menos nítidas. Questão de gosto, realmente.
E pulamos, entregamos ao matplotlib para exibir o gráfico
Em torno da parte pontiaguda da V-Shape, você vê que fiz muitos cálculos durante minha busca pelo ponto ideal, enquanto as partes menos interessantes em quase todos os lugares têm uma resolução mais baixa.
fonte
Aqui está a melhor abordagem de vizinho mais próximo de Jurgy, mas implementada usando o scipy.cKDTree . Nos meus testes, é cerca de 100x mais rápido.
fonte
Faça uma matriz bidimensional que corresponda às células da sua imagem final, chamada diga
heatmap_cells
e instancie-a como todos os zeros.Escolha dois fatores de escala que definem a diferença entre cada elemento da matriz em unidades reais, para cada dimensão, digamos
x_scale
ey_scale
. Escolha esses itens de forma que todos os seus pontos de dados caiam dentro dos limites da matriz do mapa de calor.Para cada ponto de dados bruto com
x_value
ey_value
:heatmap_cells[floor(x_value/x_scale),floor(y_value/y_scale)]+=1
fonte
Aqui está um que fiz em um milhão de pontos definido com 3 categorias (vermelho, verde e azul). Aqui está um link para o repositório, se você quiser experimentar a função. Repositório do Github
fonte
Muito semelhante à resposta de @ Piti , mas usando 1 chamada em vez de 2 para gerar os pontos:
Resultado:
fonte
Receio estar um pouco atrasado para a festa, mas tive uma pergunta semelhante há um tempo atrás. A resposta aceita (por @ptomato) me ajudou, mas eu também gostaria de postar isso, caso seja útil para alguém.
Aqui está o resultado
fonte