Como posso plotar valores NaN como uma cor especial com imshow em matplotlib?

85

Estou tentando usar imshow em matplotlib para plotar dados como um mapa de calor, mas alguns dos valores são NaNs. Gostaria que os NaNs fossem renderizados como uma cor especial não encontrada no mapa de cores.

exemplo:

import numpy as np
import matplotlib.pyplot as plt
f = plt.figure()
ax = f.add_subplot(111)
a = np.arange(25).reshape((5,5)).astype(float)
a[3,:] = np.nan
ax.imshow(a, interpolation='nearest')
f.canvas.draw()

A imagem resultante é inesperadamente toda azul (a cor mais baixa no mapa de cores do jato). No entanto, se eu fizer a plotagem assim:

ax.imshow(a, interpolation='nearest', vmin=0, vmax=24)

--então consigo algo melhor, mas os valores NaN são desenhados da mesma cor que vmin ... Existe uma maneira elegante de definir NaNs para serem desenhados com uma cor especial (por exemplo: cinza ou transparente)?

Adam Fraser
fonte
Alguns anos depois ( matplotlib.__version__=='1.2.1'), isso funciona sem problemas.
Frédéric Grosshans

Respostas:

47

Com as versões mais recentes do Matplotlib, não é mais necessário usar um array mascarado.

Por exemplo, vamos gerar uma matriz onde cada sétimo valor é um NaN:

arr = np.arange(100, dtype=float).reshape(10, 10)
arr[~(arr % 7).astype(bool)] = np.nan

Podemos modificar o mapa de cores atual e plotar a matriz com as seguintes linhas:

current_cmap = matplotlib.cm.get_cmap()
current_cmap.set_bad(color='red')
plt.imshow(arr)

resultado do enredo

Arcturus B
fonte
é possível usar 0 em vez de np.nan?
yukashima huksay
2
@yukashimahuksay: sim, mas você precisaria mascarar esses valores. Por exemplo. arr = np.ma.array(arr, mask=(arr == 0)).
Arcturus B,
Eu acho que o 'c' em 'cmap' já significa 'atual', então eu não chamaria a variável de 'current_cmap'
T. Gwen
3
@TGwen: Tenho certeza de que cmap significa colormap, que é o termo usado no documento: matplotlib.org/api/cm_api.html#matplotlib.cm.get_cmap
Arcturus B
82

Hrm, parece que posso usar uma matriz mascarada para fazer isso:

masked_array = np.ma.array (a, mask=np.isnan(a))
cmap = matplotlib.cm.jet
cmap.set_bad('white',1.)
ax.imshow(masked_array, interpolation='nearest', cmap=cmap)

Isso deve bastar, embora eu ainda esteja aberto a sugestões. :]

Adam Fraser
fonte
Definitivamente funciona. Os documentos oficiais não mostram mais nada.
Agos
6
Um ponto lado - Eu acho que fazendo isso irá substituir o padrão matplotlib.cm.jet, assim que eu costumo fazer uma cópia: import copy; cmap=copy.copy(matplotlib.cm.jet). Além disso, se você quiser definir valores 0 para uma cor diferente, algo como cmap._init(); cm._lut[:,0] = (1,1,1,1)deve funcionar.
keflavich
3
Existe também set_overe set_underpara controlar a coloração de valores fora da faixa. O comportamento padrão é combinar a parte superior / inferior da gama de cores.
tacaswell
2
O é masked_arraynecessário? Se acontiver valores NaN (assim parece mask=np.isnan(a)), então apenas imshow-ing a matriz acom o mapa personalizado cmapexibirá células NaN com a cor necessária (branco). Então, funciona para mim. Existem exceções?
MaciekS de
2
@MaciekS, ao usar um mapa de cores divergente, você não quer que seus nanvalores e valores medianos sejam plotados na mesma cor, por exemplo, branco.
AGS de