Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 89105f1

Browse files
authored
Merge pull request #14257 from greglucas/colormap_nan_handling
FIX: Changing cmap(np.nan) to 'bad' value rather than 'under' value
2 parents 6969cad + 423bd0d commit 89105f1

2 files changed

Lines changed: 70 additions & 15 deletions

File tree

lib/matplotlib/colors.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -517,15 +517,17 @@ def __call__(self, X, alpha=None, bytes=False):
517517
if not self._isinit:
518518
self._init()
519519
mask_bad = None
520-
if not np.iterable(X):
521-
vtype = 'scalar'
522-
xa = np.array([X])
523-
else:
524-
vtype = 'array'
525-
xma = np.ma.array(X, copy=True) # Copy here to avoid side effects.
526-
mask_bad = xma.mask # Mask will be used below.
527-
xa = xma.filled() # Fill to avoid infs, etc.
528-
del xma
520+
if np.ma.is_masked(X):
521+
mask_bad = X.mask
522+
elif np.any(np.isnan(X)):
523+
# mask nan's
524+
mask_bad = np.isnan(X)
525+
526+
xa = np.array(X, copy=True)
527+
# Fill bad values to avoid warnings
528+
# in the boolean comparisons below.
529+
if mask_bad is not None:
530+
xa[mask_bad] = 0.
529531

530532
# Calculations with native byteorder are faster, and avoid a
531533
# bug that otherwise can occur with putmask when the last
@@ -548,10 +550,8 @@ def __call__(self, X, alpha=None, bytes=False):
548550
xa[xa > self.N - 1] = self._i_over
549551
xa[xa < 0] = self._i_under
550552
if mask_bad is not None:
551-
if mask_bad.shape == xa.shape:
552-
np.copyto(xa, self._i_bad, where=mask_bad)
553-
elif mask_bad:
554-
xa.fill(self._i_bad)
553+
xa[mask_bad] = self._i_bad
554+
555555
if bytes:
556556
lut = (self._lut * 255).astype(np.uint8)
557557
else:
@@ -572,8 +572,9 @@ def __call__(self, X, alpha=None, bytes=False):
572572
# override its alpha just as for any other value.
573573

574574
rgba = lut.take(xa, axis=0, mode='clip')
575-
if vtype == 'scalar':
576-
rgba = tuple(rgba[0, :])
575+
if not np.iterable(X):
576+
# Return a tuple if the input was a scalar
577+
rgba = tuple(rgba)
577578
return rgba
578579

579580
def __copy__(self):

lib/matplotlib/tests/test_colors.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,60 @@ def test_colormap_endian():
7575
assert_array_equal(cmap(anative), cmap(aforeign))
7676

7777

78+
def test_colormap_invalid():
79+
"""
80+
Github issue #9892: Handling of nan's were getting mapped to under
81+
rather than bad. This tests to make sure all invalid values
82+
(-inf, nan, inf) are mapped respectively to (under, bad, over).
83+
"""
84+
cmap = cm.get_cmap("plasma")
85+
x = np.array([-np.inf, -1, 0, np.nan, .7, 2, np.inf])
86+
87+
expected = np.array([[0.050383, 0.029803, 0.527975, 1.],
88+
[0.050383, 0.029803, 0.527975, 1.],
89+
[0.050383, 0.029803, 0.527975, 1.],
90+
[0., 0., 0., 0.],
91+
[0.949217, 0.517763, 0.295662, 1.],
92+
[0.940015, 0.975158, 0.131326, 1.],
93+
[0.940015, 0.975158, 0.131326, 1.]])
94+
assert_array_equal(cmap(x), expected)
95+
96+
# Test masked representation (-inf, inf) are now masked
97+
expected = np.array([[0., 0., 0., 0.],
98+
[0.050383, 0.029803, 0.527975, 1.],
99+
[0.050383, 0.029803, 0.527975, 1.],
100+
[0., 0., 0., 0.],
101+
[0.949217, 0.517763, 0.295662, 1.],
102+
[0.940015, 0.975158, 0.131326, 1.],
103+
[0., 0., 0., 0.]])
104+
assert_array_equal(cmap(np.ma.masked_invalid(x)), expected)
105+
106+
# Test scalar representations
107+
assert_array_equal(cmap(-np.inf), cmap(0))
108+
assert_array_equal(cmap(np.inf), cmap(1.0))
109+
assert_array_equal(cmap(np.nan), np.array([0., 0., 0., 0.]))
110+
111+
112+
def test_colormap_return_types():
113+
"""
114+
Make sure that tuples are returned for scalar input and
115+
that the proper shapes are returned for ndarrays.
116+
"""
117+
cmap = cm.get_cmap("plasma")
118+
# Test return types and shapes
119+
# scalar input needs to return a tuple of length 4
120+
assert isinstance(cmap(0.5), tuple)
121+
assert len(cmap(0.5)) == 4
122+
123+
# input array returns an ndarray of shape x.shape + (4,)
124+
x = np.ones(4)
125+
assert cmap(x).shape == x.shape + (4,)
126+
127+
# multi-dimensional array input
128+
x2d = np.zeros((2, 2))
129+
assert cmap(x2d).shape == x2d.shape + (4,)
130+
131+
78132
def test_BoundaryNorm():
79133
"""
80134
Github issue #1258: interpolation was failing with numpy

0 commit comments

Comments
 (0)