¿Cómo puedo trazar los valores de NaN como un color especial con imshow en matplotlib?

85

Estoy tratando de usar imshow en matplotlib para trazar datos como un mapa de calor, pero algunos de los valores son NaN. Me gustaría que los NaN se representen como un color especial que no se encuentra en el mapa de colores.

ejemplo:

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

La imagen resultante es inesperadamente toda azul (el color más bajo en el mapa de colores del jet). Sin embargo, si hago el trazado así:

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

- luego obtengo algo mejor, pero los valores de NaN se dibujan del mismo color que vmin ... ¿Hay alguna manera elegante de configurar los NaN para que se dibujen con un color especial (por ejemplo: gris o transparente)?

Adam Fraser
fuente
Unos años más tarde ( matplotlib.__version__=='1.2.1'), esto funciona sin problemas.
Frédéric Grosshans

Respuestas:

46

Con las versiones más recientes de Matplotlib, ya no es necesario usar una matriz enmascarada.

Por ejemplo, generemos una matriz donde cada séptimo valor es un NaN:

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

Podemos modificar el mapa de colores actual y trazar la matriz con las siguientes líneas:

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

resultado de la trama

Arcturus B
fuente
¿Es posible usar 0 en lugar de np.nan?
yukashima huksay
2
@yukashimahuksay: sí, pero necesitaría enmascarar estos valores. P.ej. arr = np.ma.array(arr, mask=(arr == 0)).
Arcturus B
Creo que la 'c' en 'cmap' ya significa 'actual', por lo que no llamaría a la variable 'current_cmap'
T. Gwen
3
@TGwen: Estoy bastante seguro de que cmap significa mapa de color, que es el término utilizado en el documento: matplotlib.org/api/cm_api.html#matplotlib.cm.get_cmap
Arcturus B
82

Hrm, parece que puedo usar una matriz enmascarada para hacer esto:

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)

Esto debería ser suficiente, aunque todavía estoy abierto a sugerencias. :]

Adam Fraser
fuente
Definitivamente funciona. Los documentos oficiales no muestran nada más.
Agos
6
Un punto de lado - Creo que hacer esto anulará el valor por defecto matplotlib.cm.jet, por lo que suelen hacer una copia: import copy; cmap=copy.copy(matplotlib.cm.jet). Además, si desea establecer valores 0 en un color diferente, algo como cmap._init(); cm._lut[:,0] = (1,1,1,1)debería funcionar.
keflavich
3
También existe set_overy set_underpara controlar la coloración de los valores fuera de rango. El comportamiento predeterminado es hacer coincidir la parte superior / inferior de la gama de colores.
Tacaswell
2
¿Es masked_arraynecesario en absoluto? Si acontiene valores de NaN (lo que parece mask=np.isnan(a)), simplemente al hacer imshowla matriz acon el mapa personalizado cmapse mostrarán celdas de NaN con el color requerido (blanco). Así funciona para mí. ¿Existen excepciones?
MaciekS
2
@MaciekS, cuando utilice un mapa de colores divergente, no desea que sus nanvalores y valores medianos se tracen del mismo color, por ejemplo, blanco.
AGS