From dd94ac37a168b6edd3f38ee80c4a7df347d5e673 Mon Sep 17 00:00:00 2001 From: Ruth Comer <10599679+rcomer@users.noreply.github.com> Date: Sun, 3 Mar 2024 15:37:35 +0000 Subject: [PATCH] FIX: handle nans in RGBA input with ScalarMappables --- lib/matplotlib/cm.py | 8 +++++++- lib/matplotlib/tests/test_colors.py | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/cm.py b/lib/matplotlib/cm.py index 7e46cf567f70..e9a7aad6c456 100644 --- a/lib/matplotlib/cm.py +++ b/lib/matplotlib/cm.py @@ -328,7 +328,7 @@ def to_rgba(self, x, alpha=None, bytes=False, norm=True): treated as an RGB or RGBA array, and no mapping will be done. The array can be `~numpy.uint8`, or it can be floats with values in the 0-1 range; otherwise a ValueError will be raised. - If it is a masked array, any masked elements will be set to 0 alpha. + Any NaNs or masked elements will be set to 0 alpha. If the last dimension is 3, the *alpha* kwarg (defaulting to 1) will be used to fill in the transparency. If the last dimension is 4, the *alpha* kwarg is ignored; it does not @@ -360,6 +360,12 @@ def to_rgba(self, x, alpha=None, bytes=False, norm=True): else: raise ValueError("Third dimension must be 3 or 4") if xx.dtype.kind == 'f': + # If any of R, G, B, or A is nan, set to 0 + if np.any(nans := np.isnan(x)): + if xx.shape[2] == 4: + xx = xx.copy() + xx[np.any(nans, axis=2), :] = 0 + if norm and (xx.max() > 1 or xx.min() < 0): raise ValueError("Floating point image RGB values " "must be in the 0..1 range.") diff --git a/lib/matplotlib/tests/test_colors.py b/lib/matplotlib/tests/test_colors.py index 2d71fea83472..5b5332100c2a 100644 --- a/lib/matplotlib/tests/test_colors.py +++ b/lib/matplotlib/tests/test_colors.py @@ -1352,6 +1352,32 @@ def test_scalarmappable_to_rgba(bytes): np.testing.assert_almost_equal(sm.to_rgba(xm[..., :3], bytes=bytes), expected) +@pytest.mark.parametrize("bytes", (True, False)) +def test_scalarmappable_nan_to_rgba(bytes): + sm = cm.ScalarMappable() + + # RGBA + x = np.ones((2, 3, 4), dtype=float) * 0.5 + x[0, 0, 0] = np.nan + expected = x.copy() + expected[0, 0, :] = 0 + if bytes: + expected = (expected * 255).astype(np.uint8) + np.testing.assert_almost_equal(sm.to_rgba(x, bytes=bytes), expected) + assert np.any(np.isnan(x)) # Input array should not be changed + + # RGB + expected[..., 3] = 255 if bytes else 1 + expected[0, 0, 3] = 0 + np.testing.assert_almost_equal(sm.to_rgba(x[..., :3], bytes=bytes), expected) + assert np.any(np.isnan(x)) # Input array should not be changed + + # Out-of-range fail + x[1, 0, 0] = 42 + with pytest.raises(ValueError, match='0..1 range'): + sm.to_rgba(x[..., :3], bytes=bytes) + + def test_failed_conversions(): with pytest.raises(ValueError): mcolors.to_rgba('5') pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy