Traçando um mapa de calor 2D com o Matplotlib

139

Usando o Matplotlib, quero traçar um mapa de calor 2D. Meus dados são uma matriz Numpy n por n, cada uma com um valor entre 0 e 1. Portanto, para o elemento (i, j) dessa matriz, quero plotar um quadrado na coordenada (i, j) na minha mapa de calor, cuja cor é proporcional ao valor do elemento na matriz.

Como posso fazer isso?

Karnivaurus
fonte
2
você olhou a matplotlibgaleria antes de postar? Há alguns exemplos bons usando imshow, pcolore pcolormeshque fazer o que quiser
tmdavison
Possível duplicado de multi colored erro de Mapa de Calor Python
jkalden

Respostas:

187

A imshow()função com parâmetros interpolation='nearest'e cmap='hot'deve fazer o que você deseja.

import matplotlib.pyplot as plt
import numpy as np

a = np.random.random((16, 16))
plt.imshow(a, cmap='hot', interpolation='nearest')
plt.show()

insira a descrição da imagem aqui

P. Camilleri
fonte
1
Não acho que especificar interpolação seja necessário.
Miguel.martin 28/03
2
@ miguel.martin conforme o documento do pyplot: "Se a interpolação for None (seu valor padrão), o padrão será rc image.interpolation". Então eu acho que é necessário incluí-lo.
P. Camilleri 28/03
@ P.Camilleri Como escalar os eixos X e Y? (Altere apenas os números, sem zoom).
Dole
64

O Seaborn cuida de muito do trabalho manual e plota automaticamente um gradiente ao lado do gráfico, etc.

import numpy as np
import seaborn as sns
import matplotlib.pylab as plt

uniform_data = np.random.rand(10, 12)
ax = sns.heatmap(uniform_data, linewidth=0.5)
plt.show()

insira a descrição da imagem aqui

Ou ainda, você pode plotar triângulos superior / inferior esquerdo / direito de matrizes quadradas, por exemplo, uma matriz de correlação quadrada e simétrica; portanto, plotar todos os valores seria redundante de qualquer maneira.

corr = np.corrcoef(np.random.randn(10, 200))
mask = np.zeros_like(corr)
mask[np.triu_indices_from(mask)] = True
with sns.axes_style("white"):
    ax = sns.heatmap(corr, mask=mask, vmax=.3, square=True,  cmap="YlGnBu")
    plt.show()

insira a descrição da imagem aqui

PyRsquared
fonte
1
Gosto muito do tipo de enredo, e a meia matriz é útil. Duas perguntas: 1) no primeiro gráfico, os pequenos quadrados são separados por linhas brancas, poderiam ser unidos? 2) a largura da linha branca parece variar, isso é um artefato?
31318 Camberi P.
1
Você pode usar o argumento 'largura de linha' que usei no primeiro gráfico para qualquer outro gráfico (no segundo gráfico, por exemplo), para obter quadrados espaçados. As larguras das linhas parecem variar apenas no primeiro gráfico devido a problemas de captura de tela, na verdade não variam na realidade, devem permanecer na constante que você as definiu.
PyRsquared 29/04/19
enquanto isso é verdade - não acho que uma resposta usando o transporte marítimo deva ser considerada completa para uma pergunta que especifique especificamente o matplotlib.
baxx
28

Para uma numpymatriz 2D , basta usar imshow()pode ajudá-lo:

import matplotlib.pyplot as plt
import numpy as np


def heatmap2d(arr: np.ndarray):
    plt.imshow(arr, cmap='viridis')
    plt.colorbar()
    plt.show()


test_array = np.arange(100 * 100).reshape(100, 100)
heatmap2d(test_array)

O mapa de calor do código de exemplo

Este código produz um mapa de calor contínuo.

Você pode escolher outro built-in a colormappartir daqui .

huangbiubiu
fonte
18

Eu usaria a função pcolor / pcolormesh do matplotlib, pois permite o espaçamento não uniforme dos dados.

Exemplo retirado do matplotlib :

import matplotlib.pyplot as plt
import numpy as np

# generate 2 2d grids for the x & y bounds
y, x = np.meshgrid(np.linspace(-3, 3, 100), np.linspace(-3, 3, 100))

z = (1 - x / 2. + x ** 5 + y ** 3) * np.exp(-x ** 2 - y ** 2)
# x and y are bounds, so z should be the value *inside* those bounds.
# Therefore, remove the last value from the z array.
z = z[:-1, :-1]
z_min, z_max = -np.abs(z).max(), np.abs(z).max()

fig, ax = plt.subplots()

c = ax.pcolormesh(x, y, z, cmap='RdBu', vmin=z_min, vmax=z_max)
ax.set_title('pcolormesh')
# set the limits of the plot to the limits of the data
ax.axis([x.min(), x.max(), y.min(), y.max()])
fig.colorbar(c, ax=ax)

plt.show()

saída da plotagem pcolormesh

Erasmus Cedernaes
fonte
12

Veja como fazer isso em um csv:

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import griddata

# Load data from CSV
dat = np.genfromtxt('dat.xyz', delimiter=' ',skip_header=0)
X_dat = dat[:,0]
Y_dat = dat[:,1]
Z_dat = dat[:,2]

# Convert from pandas dataframes to numpy arrays
X, Y, Z, = np.array([]), np.array([]), np.array([])
for i in range(len(X_dat)):
        X = np.append(X, X_dat[i])
        Y = np.append(Y, Y_dat[i])
        Z = np.append(Z, Z_dat[i])

# create x-y points to be used in heatmap
xi = np.linspace(X.min(), X.max(), 1000)
yi = np.linspace(Y.min(), Y.max(), 1000)

# Z is a matrix of x-y values
zi = griddata((X, Y), Z, (xi[None,:], yi[:,None]), method='cubic')

# I control the range of my colorbar by removing data 
# outside of my range of interest
zmin = 3
zmax = 12
zi[(zi<zmin) | (zi>zmax)] = None

# Create the contour plot
CS = plt.contourf(xi, yi, zi, 15, cmap=plt.cm.rainbow,
                  vmax=zmax, vmin=zmin)
plt.colorbar()  
plt.show()

onde dat.xyzestá na forma

x1 y1 z1
x2 y2 z2
...
quilojoules
fonte
1
Apenas um aviso: eu tive que mudar o método de cúbico para mais próximo ou linear porque o cúbico resultou em muitos NaNs, pois estou trabalhando com valores bastante pequenos entre 0..1
Maikefer