From fcf1c0c97dd91fb989e83171140e0eee6282bc41 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 6 Oct 2022 18:00:01 -0400 Subject: [PATCH 1/5] FIX: add missing method to ColormapRegistry After putting pending deprecations on `cm.get_cmap` we discovered that downstream libraries (pandas) were using the deprecated method to normalize between `None` (to get the default colormap), strings, and Colormap instances. This adds a method to `ColormapRegistry` to do this normalization. This can not replace our internal helper due to variations in what exceptions are raised. Closes #23981 --- .../api_changes_3.6.0/deprecations.rst | 10 ++++- lib/matplotlib/cm.py | 43 ++++++++++++++++++- lib/matplotlib/tests/test_colors.py | 15 +++++++ 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/doc/api/prev_api_changes/api_changes_3.6.0/deprecations.rst b/doc/api/prev_api_changes/api_changes_3.6.0/deprecations.rst index d59077d2b2d2..028262af43d0 100644 --- a/doc/api/prev_api_changes/api_changes_3.6.0/deprecations.rst +++ b/doc/api/prev_api_changes/api_changes_3.6.0/deprecations.rst @@ -52,7 +52,13 @@ In Matplotlib 3.6 we have marked those top level functions as pending deprecation with the intention of deprecation in Matplotlib 3.7. The following functions have been marked for pending deprecation: -- ``matplotlib.cm.get_cmap``; use ``matplotlib.colormaps[name]`` instead +- ``matplotlib.cm.get_cmap``; use ``matplotlib.colormaps[name]`` instead if you + have a `str`. + + **Added 3.6.1** Use `matplotlib.cm.ColormapRegistry.get_cmap` if you + have a string, `None` or a `matplotlib.colors.Colormap` object that you want + to convert to a `matplotlib.colors.Colormap` instance. Raises `KeyError` + rather than `ValueError` for missing strings. - ``matplotlib.cm.register_cmap``; use `matplotlib.colormaps.register <.ColormapRegistry.register>` instead - ``matplotlib.cm.unregister_cmap``; use `matplotlib.colormaps.unregister @@ -305,7 +311,7 @@ Backend-specific deprecations private functions if you rely on it. - ``backend_svg.generate_transform`` and ``backend_svg.generate_css`` - ``backend_tk.NavigationToolbar2Tk.lastrect`` and - ``backend_tk.RubberbandTk.lastrect`` + ``backend_tk.RubberbandTk.lastrect`` - ``backend_tk.NavigationToolbar2Tk.window``; use ``toolbar.master`` instead. - ``backend_tools.ToolBase.destroy``; To run code upon tool removal, connect to the ``tool_removed_event`` event. diff --git a/lib/matplotlib/cm.py b/lib/matplotlib/cm.py index f6e5ee8b7156..c138fb14e907 100644 --- a/lib/matplotlib/cm.py +++ b/lib/matplotlib/cm.py @@ -193,6 +193,39 @@ def unregister(self, name): "colormap.") self._cmaps.pop(name, None) + def get_cmap(self, cmap): + """ + Ensure that at given object is a converted to a color map. + + If *cmap* in `None`, returns the Colormap named by :rc:`image.cmap`. + + Parameters + ---------- + cmap : str, Colormap, None + + - if a `~matplotlib.colors.Colormap`, return it + - if a string, look it up in mpl.colormaps + - if None, look up the default color map in mpl.colormaps + + Returns + ------- + Colormap + + Raises + ------ + KeyError + """ + # get the default color map + if cmap is None: + return self[mpl.rcParams["image.cmap"]] + + # if the user passed in a Colormap, simply return it + if isinstance(cmap, colors.Colormap): + return cmap + + # otherwise, it must be a string so look it up + return self[cmap] + # public access to the colormaps should be via `matplotlib.colormaps`. For now, # we still create the registry here, but that should stay an implementation @@ -281,7 +314,12 @@ def _get_cmap(name=None, lut=None): # pyplot. get_cmap = _api.deprecated( '3.6', - name='get_cmap', pending=True, alternative="``matplotlib.colormaps[name]``" + name='get_cmap', + pending=True, + alternative=( + "``matplotlib.colormaps[name]`` " + + "or ``matplotlib.colormaps.get_cmap(obj)``" + ) )(_get_cmap) @@ -687,6 +725,8 @@ def _ensure_cmap(cmap): """ Ensure that we have a `.Colormap` object. + For internal use to preserve type stability of errors. + Parameters ---------- cmap : None, str, Colormap @@ -698,6 +738,7 @@ def _ensure_cmap(cmap): Returns ------- Colormap + """ if isinstance(cmap, colors.Colormap): return cmap diff --git a/lib/matplotlib/tests/test_colors.py b/lib/matplotlib/tests/test_colors.py index f0c23038e11a..711fecf43e11 100644 --- a/lib/matplotlib/tests/test_colors.py +++ b/lib/matplotlib/tests/test_colors.py @@ -109,6 +109,21 @@ def test_register_cmap(): cm.register_cmap('nome', cmap='not a cmap') +def test_ensure_cmap(): + cr = mpl.colormaps + new_cm = mcolors.ListedColormap(cr["viridis"].colors, name='v2') + + # check None, str, and Colormap pass + assert cr.get_cmap('plasma') == cr["plasma"] + assert cr.get_cmap(cr["magma"]) == cr["magma"] + + # check default default + assert cr.get_cmap(None) == cr[mpl.rcParams['image.cmap']] + bad_cmap = 'AardvarksAreAwkward' + with pytest.raises(KeyError, match=bad_cmap): + cr.get_cmap(bad_cmap) + + def test_double_register_builtin_cmap(): name = "viridis" match = f"Re-registering the builtin cmap {name!r}." From 3f99c20e649fd0d533332ee4e3b4102e07d0b7f2 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 6 Oct 2022 18:47:56 -0400 Subject: [PATCH 2/5] DOC: remove note about ColormapRegistry being experimental We are committed now! --- lib/matplotlib/cm.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/matplotlib/cm.py b/lib/matplotlib/cm.py index c138fb14e907..20842f0e19c7 100644 --- a/lib/matplotlib/cm.py +++ b/lib/matplotlib/cm.py @@ -61,12 +61,6 @@ class ColormapRegistry(Mapping): r""" Container for colormaps that are known to Matplotlib by name. - .. admonition:: Experimental - - While we expect the API to be final, we formally mark it as - experimental for 3.5 because we want to keep the option to still adapt - the API for 3.6 should the need arise. - The universal registry instance is `matplotlib.colormaps`. There should be no need for users to instantiate `.ColormapRegistry` themselves. From b8bdcf84e6f52c70078f6eeb49f0c420464d3425 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Fri, 7 Oct 2022 15:15:16 -0400 Subject: [PATCH 3/5] DOC: fix formatting and wording Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- lib/matplotlib/cm.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/matplotlib/cm.py b/lib/matplotlib/cm.py index 20842f0e19c7..254efdd95fca 100644 --- a/lib/matplotlib/cm.py +++ b/lib/matplotlib/cm.py @@ -189,17 +189,15 @@ def unregister(self, name): def get_cmap(self, cmap): """ - Ensure that at given object is a converted to a color map. - - If *cmap* in `None`, returns the Colormap named by :rc:`image.cmap`. + Return a color map specified through *cmap*. Parameters ---------- - cmap : str, Colormap, None + cmap : str or `~matplotlib.colors.Colormap` or None - - if a `~matplotlib.colors.Colormap`, return it - - if a string, look it up in mpl.colormaps - - if None, look up the default color map in mpl.colormaps + - if a `.Colormap`, return it + - if a string, look it up in ``mpl.colormaps`` + - if None, return the Colormap defined in :rc:`image.cmap` Returns ------- From d0a240a1170c60be449a9ad7de9d3d30ab417f92 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Fri, 7 Oct 2022 15:15:29 -0400 Subject: [PATCH 4/5] MNT: fix test name Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- lib/matplotlib/tests/test_colors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_colors.py b/lib/matplotlib/tests/test_colors.py index 711fecf43e11..3b4a775c5379 100644 --- a/lib/matplotlib/tests/test_colors.py +++ b/lib/matplotlib/tests/test_colors.py @@ -109,7 +109,7 @@ def test_register_cmap(): cm.register_cmap('nome', cmap='not a cmap') -def test_ensure_cmap(): +def test_colormaps_get_cmap(): cr = mpl.colormaps new_cm = mcolors.ListedColormap(cr["viridis"].colors, name='v2') From 4f8ece457ba0d979813d6e992c3d6562cd7db2d0 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Fri, 7 Oct 2022 17:10:04 -0400 Subject: [PATCH 5/5] MNT: raise ValueError and TypeError rather than KeyError --- .../api_changes_3.6.0/deprecations.rst | 3 +-- lib/matplotlib/cm.py | 15 ++++++++------- lib/matplotlib/tests/test_colors.py | 13 +++++++++---- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/doc/api/prev_api_changes/api_changes_3.6.0/deprecations.rst b/doc/api/prev_api_changes/api_changes_3.6.0/deprecations.rst index 028262af43d0..3a9e91e12289 100644 --- a/doc/api/prev_api_changes/api_changes_3.6.0/deprecations.rst +++ b/doc/api/prev_api_changes/api_changes_3.6.0/deprecations.rst @@ -57,8 +57,7 @@ functions have been marked for pending deprecation: **Added 3.6.1** Use `matplotlib.cm.ColormapRegistry.get_cmap` if you have a string, `None` or a `matplotlib.colors.Colormap` object that you want - to convert to a `matplotlib.colors.Colormap` instance. Raises `KeyError` - rather than `ValueError` for missing strings. + to convert to a `matplotlib.colors.Colormap` instance. - ``matplotlib.cm.register_cmap``; use `matplotlib.colormaps.register <.ColormapRegistry.register>` instead - ``matplotlib.cm.unregister_cmap``; use `matplotlib.colormaps.unregister diff --git a/lib/matplotlib/cm.py b/lib/matplotlib/cm.py index 254efdd95fca..ec0d472992ef 100644 --- a/lib/matplotlib/cm.py +++ b/lib/matplotlib/cm.py @@ -202,10 +202,6 @@ def get_cmap(self, cmap): Returns ------- Colormap - - Raises - ------ - KeyError """ # get the default color map if cmap is None: @@ -214,9 +210,14 @@ def get_cmap(self, cmap): # if the user passed in a Colormap, simply return it if isinstance(cmap, colors.Colormap): return cmap - - # otherwise, it must be a string so look it up - return self[cmap] + if isinstance(cmap, str): + _api.check_in_list(sorted(_colormaps), cmap=cmap) + # otherwise, it must be a string so look it up + return self[cmap] + raise TypeError( + 'get_cmap expects None or an instance of a str or Colormap . ' + + f'you passed {cmap!r} of type {type(cmap)}' + ) # public access to the colormaps should be via `matplotlib.colormaps`. For now, diff --git a/lib/matplotlib/tests/test_colors.py b/lib/matplotlib/tests/test_colors.py index 3b4a775c5379..86536ab17234 100644 --- a/lib/matplotlib/tests/test_colors.py +++ b/lib/matplotlib/tests/test_colors.py @@ -111,18 +111,23 @@ def test_register_cmap(): def test_colormaps_get_cmap(): cr = mpl.colormaps - new_cm = mcolors.ListedColormap(cr["viridis"].colors, name='v2') - # check None, str, and Colormap pass + # check str, and Colormap pass assert cr.get_cmap('plasma') == cr["plasma"] assert cr.get_cmap(cr["magma"]) == cr["magma"] - # check default default + # check default assert cr.get_cmap(None) == cr[mpl.rcParams['image.cmap']] + + # check ValueError on bad name bad_cmap = 'AardvarksAreAwkward' - with pytest.raises(KeyError, match=bad_cmap): + with pytest.raises(ValueError, match=bad_cmap): cr.get_cmap(bad_cmap) + # check TypeError on bad type + with pytest.raises(TypeError, match='object'): + cr.get_cmap(object()) + def test_double_register_builtin_cmap(): name = "viridis" 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