Comment puis-je tracer les valeurs NaN comme une couleur spéciale avec imshow dans matplotlib?

85

J'essaie d'utiliser imshow dans matplotlib pour tracer des données sous forme de carte thermique, mais certaines des valeurs sont des NaN. Je voudrais que les NaN soient rendus comme une couleur spéciale introuvable dans la palette de couleurs.

exemple:

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

L'image résultante est de façon inattendue entièrement bleue (la couleur la plus basse de la palette de couleurs du jet). Cependant, si je fais le tracé comme ceci:

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

- alors j'obtiens quelque chose de mieux, mais les valeurs NaN sont dessinées de la même couleur que vmin ... Y a-t-il une manière gracieuse de définir les NaN à dessiner avec une couleur spéciale (par exemple: gris ou transparent)?

Adam Fraser
la source
Quelques années plus tard ( matplotlib.__version__=='1.2.1'), cela fonctionne sans problème.
Frédéric Grosshans

Réponses:

46

Avec les nouvelles versions de Matplotlib, il n'est plus nécessaire d'utiliser un tableau masqué.

Par exemple, générons un tableau où chaque 7ème valeur est un NaN:

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

Nous pouvons modifier la palette de couleurs actuelle et tracer le tableau avec les lignes suivantes:

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

résultat du tracé

Arcturus B
la source
est-il possible d'utiliser 0 au lieu de np.nan?
yukashima huksay
2
@yukashimahuksay: oui, mais vous auriez besoin de masquer ces valeurs. Par exemple. arr = np.ma.array(arr, mask=(arr == 0)).
Arcturus B
Je pense que le «c» dans «cmap» signifie déjà «courant», donc je n'appellerais pas la variable «current_cmap»
T.Gwen
3
@TGwen: Je suis presque sûr que cmap signifie colormap, qui est le terme utilisé dans le doc: matplotlib.org/api/cm_api.html#matplotlib.cm.get_cmap
Arcturus B
82

Hrm, il semble que je puisse utiliser un tableau masqué pour faire ceci:

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)

Cela devrait suffire, même si je suis toujours ouvert aux suggestions. :]

Adam Fraser
la source
Cela fait définitivement l'affaire. Les documents officiels ne montrent rien de plus.
Agos
6
Un point de côté - Je pense faire cela remplacera la valeur par défaut matplotlib.cm.jet, donc je fais d' habitude une copie: import copy; cmap=copy.copy(matplotlib.cm.jet). De plus, si vous souhaitez définir des valeurs 0 sur une couleur différente, quelque chose comme ça cmap._init(); cm._lut[:,0] = (1,1,1,1)devrait fonctionner.
keflavich
3
Il y a aussi set_overet set_underpour contrôler la coloration des valeurs hors limites. Le comportement par défaut est de faire correspondre le haut / le bas de la gamme de couleurs.
tacaswell
2
Est-ce masked_arrayvraiment nécessaire? Si acontient des valeurs NaN (cela semble être le cas mask=np.isnan(a)), alors un simple imshowclic sur le tableau aavec la carte personnalisée cmapaffichera les cellules NaN avec la couleur requise (blanc). Donc ça marche pour moi. Y a-t-il des exceptions?
MaciekS
2
@MaciekS, lorsque vous utilisez une palette de couleurs divergente, vous ne voulez pas que vos nanvaleurs et valeurs médianes soient tracées de la même couleur, par exemple le blanc.
AGS