From 40f40137ca027c45bb318c41cff80c337e57224b Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Thu, 17 Sep 2020 00:57:16 +0200 Subject: [PATCH 1/2] Add a dedicated ColormapRegistry class --- .flake8 | 2 +- doc/api/matplotlib_configuration_api.rst | 6 ++ doc/users/next_whats_new/colormaps.rst | 18 ++++++ lib/matplotlib/__init__.py | 5 ++ lib/matplotlib/cm.py | 77 +++++++++++++++++++++++- 5 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 doc/users/next_whats_new/colormaps.rst diff --git a/.flake8 b/.flake8 index 2d16a348e734..06ad576c1b19 100644 --- a/.flake8 +++ b/.flake8 @@ -45,7 +45,7 @@ per-file-ignores = setupext.py: E501 tests.py: F401 - lib/matplotlib/__init__.py: F401 + lib/matplotlib/__init__.py: E402, F401 lib/matplotlib/_api/__init__.py: F401 lib/matplotlib/_cm.py: E122, E202, E203, E302 lib/matplotlib/_mathtext.py: E221, E251 diff --git a/doc/api/matplotlib_configuration_api.rst b/doc/api/matplotlib_configuration_api.rst index 5fa27bbc6723..3636c45d0c71 100644 --- a/doc/api/matplotlib_configuration_api.rst +++ b/doc/api/matplotlib_configuration_api.rst @@ -52,6 +52,12 @@ Logging .. autofunction:: set_loglevel +Colormaps +========= + +.. autodata:: colormaps + :no-value: + Miscellaneous ============= diff --git a/doc/users/next_whats_new/colormaps.rst b/doc/users/next_whats_new/colormaps.rst new file mode 100644 index 000000000000..549a61892cb4 --- /dev/null +++ b/doc/users/next_whats_new/colormaps.rst @@ -0,0 +1,18 @@ +Colormaps registry +------------------ + +Colormaps are now managed via `matplotlib.colormaps`, which is a +`.ColormapRegistry`. + +Colormaps can be obtained using item access:: + + import matplotlib as mpl + cmap = mpl.colormaps['viridis'] + +To register new colormaps use:: + + mpl.colormaps.register(my_colormap) + +The use of `matplotlib.cm.get_cmap` and `matplotlib.cm.register_cmap` is +discouraged in favor of the above. Within `.pyplot` the use of +``plt.get_cmap()`` and ``plt.register_cmap()`` will continue to be supported. \ No newline at end of file diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index a62ab3e5cc46..ca66f5a53ed9 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1445,3 +1445,8 @@ def inner(ax, *args, data=None, **kwargs): _log.debug('interactive is %s', is_interactive()) _log.debug('platform is %s', sys.platform) _log.debug('loaded modules: %s', list(sys.modules)) + + +# workaround: we must defer colormaps import to after loading rcParams, because +# colormap creation depends on rcParams +from matplotlib.cm import _colormaps as colormaps diff --git a/lib/matplotlib/cm.py b/lib/matplotlib/cm.py index 6d05be943b33..a44e1579b88b 100644 --- a/lib/matplotlib/cm.py +++ b/lib/matplotlib/cm.py @@ -15,7 +15,7 @@ normalization. """ -from collections.abc import MutableMapping +from collections.abc import Mapping, MutableMapping import numpy as np from numpy import ma @@ -91,13 +91,86 @@ def _warn_deprecated(self): ) +class ColormapRegistry(Mapping): + r""" + Container for colormaps that are known to Matplotlib by name. + + The universal registry instance is `matplotlib.colormaps`. There should be + no need for users to instantiate `.ColormapRegistry` themselves. + + Read access uses a dict-like interface mapping names to `.Colormap`\s:: + + import matplotlib as mpl + cmap = mpl.colormaps['viridis'] + + Returned `.Colormap`\s are copies, so that their modification does not + change the global definition of the colormap. + + Additional colormaps can be added via `.ColormapRegistry.register`:: + + mpl.colormaps.register(my_colormap) + """ + def __init__(self, cmaps): + self._cmaps = cmaps + + def __getitem__(self, item): + try: + return self._cmaps[item].copy() + except KeyError: + raise KeyError(f"{item!r} is not a known colormap name") + + def __iter__(self): + return iter(self._cmaps) + + def __len__(self): + return len(self._cmaps) + + def __str__(self): + return ('ColormapRegistry; available colormaps:\n' + + ', '.join(f"'{name}'" for name in self)) + + def register(self, cmap, *, name=None, force=False): + """ + Register a new colormap. + + The colormap name can then be used as a string argument to any ``cmap`` + parameter in Matplotlib. It is also available in ``pyplot.get_cmap``. + + The colormap registry stores a copy of the given colormap, so that + future changes to the original colormap instance do not affect the + registered colormap. Think of this as the registry taking a snapshot + of the colormap at registration. + + Parameters + ---------- + cmap : matplotlib.colors.Colormap + The colormap to register. + + name : str, optional + The name for the colormap. If not given, ``cmap.name`` is used. + + force: bool, default: False + If False, a ValueError is raised if trying to overwrite an already + registered name. True supports overwriting registered colormaps + other than the builtin colormaps. + """ + name = name or cmap.name + if name in self and not force: + raise ValueError( + f'A colormap named "{name}" is already registered.') + register_cmap(name, cmap.copy()) + + _cmap_registry = _gen_cmap_registry() globals().update(_cmap_registry) # This is no longer considered public API cmap_d = _DeprecatedCmapDictWrapper(_cmap_registry) __builtin_cmaps = tuple(_cmap_registry) -# Continue with definitions ... +# public acces to the colormaps should be via `matplotlib.colormaps`. For now, +# we still create the registry here, but that should stay an implementation +# detail. +_colormaps = ColormapRegistry(_cmap_registry) def register_cmap(name=None, cmap=None, *, override_builtin=False): From 3f4ab7ff8813178f94bd9569c7802c97194908ad Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Sun, 15 Aug 2021 00:46:25 +0200 Subject: [PATCH 2/2] Update doc/users/next_whats_new/colormaps.rst Co-authored-by: Greg Lucas --- doc/users/next_whats_new/colormaps.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/users/next_whats_new/colormaps.rst b/doc/users/next_whats_new/colormaps.rst index 549a61892cb4..5262fab305da 100644 --- a/doc/users/next_whats_new/colormaps.rst +++ b/doc/users/next_whats_new/colormaps.rst @@ -1,4 +1,4 @@ -Colormaps registry +Colormap registry ------------------ Colormaps are now managed via `matplotlib.colormaps`, which is a