Wie kann ich NaN-Werte als Sonderfarbe mit imshow in matplotlib darstellen?

84

Ich versuche, imshow in matplotlib zu verwenden, um Daten als Heatmap zu zeichnen, aber einige der Werte sind NaNs. Ich möchte, dass die NaNs als Sonderfarbe gerendert werden, die in der Farbkarte nicht enthalten ist.

Beispiel:

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

Das resultierende Bild ist unerwartet ganz blau (die niedrigste Farbe in der Jet-Farbkarte). Wenn ich das Plotten jedoch so mache:

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

--dann bekomme ich etwas Besseres, aber die NaN-Werte werden in derselben Farbe wie vmin gezeichnet ... Gibt es eine elegante Möglichkeit, NaNs so einzustellen, dass sie mit einer speziellen Farbe gezeichnet werden (z. B. grau oder transparent)?

Adam Fraser
quelle
Einige Jahre später ( matplotlib.__version__=='1.2.1') funktioniert dies problemlos.
Frédéric Grosshans

Antworten:

42

Bei neueren Versionen von Matplotlib ist es nicht mehr erforderlich, ein maskiertes Array zu verwenden.

Lassen Sie uns zum Beispiel ein Array generieren, bei dem jeder 7. Wert ein NaN ist:

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

Wir können die aktuelle Farbkarte ändern und das Array mit den folgenden Zeilen zeichnen:

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

Plot-Ergebnis

Arcturus B.
quelle
ist es möglich, 0 anstelle von np.nan zu verwenden?
Yukashima Huksay
2
@yukashimahuksay: Ja, aber Sie müssten diese Werte maskieren. Z.B. arr = np.ma.array(arr, mask=(arr == 0)).
Arcturus B
Ich denke, das 'c' in 'cmap' steht bereits für 'current', daher würde ich die Variable 'current_cmap' nicht aufrufen
T. Gwen
3
@TGwen: Ich bin mir ziemlich sicher, dass cmap für colormap steht, was der Begriff ist, der im Dokument verwendet wird: matplotlib.org/api/cm_api.html#matplotlib.cm.get_cmap
Arcturus B
80

Hrm, anscheinend kann ich dazu ein maskiertes Array verwenden:

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)

Dies sollte ausreichen, obwohl ich immer noch offen für Vorschläge bin. :]

Adam Fraser
quelle
Es macht definitiv den Trick. Offizielle Dokumente zeigen nichts mehr.
Agos
6
Ein Nebenpunkt - Ich denke, dies überschreibt die Standardeinstellung matplotlib.cm.jet, daher erstelle ich normalerweise eine Kopie : import copy; cmap=copy.copy(matplotlib.cm.jet). Wenn Sie 0-Werte auf eine andere Farbe setzen möchten, sollte so etwas cmap._init(); cm._lut[:,0] = (1,1,1,1)funktionieren.
Keflavich
3
Es gibt auch set_overund set_underzur Steuerung der Färbung von Werten außerhalb des Bereichs. Das Standardverhalten besteht darin, mit dem oberen / unteren Rand des Farbbereichs übereinzustimmen.
Tacaswell
2
Ist das überhaupt masked_arrayerforderlich? Wenn aNaN-Werte enthalten sind (so scheint es mask=np.isnan(a)), werden durch imshoweinfaches aAnpassen des Arrays mit der benutzerdefinierten Karte cmapNaN-Zellen mit der erforderlichen Farbe (weiß) angezeigt. So funktioniert es bei mir. Gibt es Ausnahmen?
MaciekS
2
@MaciekS Wenn Sie eine divergierende Farbkarte verwenden, möchten Sie nicht, dass Ihre nanWerte und Medianwerte in derselben Farbe dargestellt werden, z. B. Weiß.
AGS