Skip to content

Commit 79f414a

Browse files
committed
Add a dedicated ColormapRegistry class
1 parent 2967365 commit 79f414a

File tree

5 files changed

+103
-3
lines changed

5 files changed

+103
-3
lines changed

.flake8

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ per-file-ignores =
4545
setupext.py: E501
4646
tests.py: F401
4747

48-
lib/matplotlib/__init__.py: F401
48+
lib/matplotlib/__init__.py: E402, F401
4949
lib/matplotlib/_api/__init__.py: F401
5050
lib/matplotlib/_cm.py: E122, E202, E203, E302
5151
lib/matplotlib/_mathtext.py: E221, E251

doc/api/matplotlib_configuration_api.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ Logging
5252

5353
.. autofunction:: set_loglevel
5454

55+
Colormaps
56+
=========
57+
58+
.. autodata:: colormaps
59+
5560
Miscellaneous
5661
=============
5762

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Colormaps registry
2+
------------------
3+
4+
Colormaps are now managed via `matplotlib.colormaps`, which is a
5+
`.ColormapRegistry`.
6+
7+
Colormaps can be obtained using item access::
8+
9+
import matplotlib as mpl
10+
cmap = mpl.colormaps['viridis']
11+
12+
To register new colormaps use::
13+
14+
mpl.colormaps.register(my_colormap)
15+
16+
The use of `matplotlib.cm.get_cmap` and `matplotlib.cm.register_cmap` is
17+
discouraged in favor of the above. Within `.pyplot` the use of
18+
``plt.get_cmap()`` and ``plt.register_cmap()`` will continue to be supported.

lib/matplotlib/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1445,3 +1445,8 @@ def inner(ax, *args, data=None, **kwargs):
14451445
_log.debug('interactive is %s', is_interactive())
14461446
_log.debug('platform is %s', sys.platform)
14471447
_log.debug('loaded modules: %s', list(sys.modules))
1448+
1449+
1450+
# workaround: we must defer colormaps import to after loading rcParams, becuase
1451+
# colormap creation depends on rcParams
1452+
from matplotlib.cm import _colormaps as colormaps

lib/matplotlib/cm.py

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
normalization.
1616
"""
1717

18-
from collections.abc import MutableMapping
18+
from collections.abc import Mapping, MutableMapping
1919

2020
import numpy as np
2121
from numpy import ma
@@ -91,13 +91,85 @@ def _warn_deprecated(self):
9191
)
9292

9393

94+
class ColormapRegistry(Mapping):
95+
r"""
96+
Container for colormaps that are known to Matplotlib by name.
97+
98+
The universal registry instance is `matplotlib.colormaps`. There should be
99+
no need for users to instantiate `.ColormapRegistry` themselves.
100+
101+
Read access uses a dict-like interface mapping names to `.Colormap`\s::
102+
103+
import matplotlib as mpl
104+
cmap = mpl.colormaps['viridis']
105+
106+
Returned `.Colormap`\s are copies, so that their modification does not
107+
change the global definition of the colormap.
108+
109+
Additional colormaps can be added via `.ColormapRegistry.register`::
110+
111+
mpl.colormaps.register(my_colormap)
112+
"""
113+
def __init__(self, cmaps):
114+
self._cmaps = cmaps
115+
116+
def __getitem__(self, item):
117+
try:
118+
return self._cmaps[item].copy()
119+
except KeyError:
120+
raise KeyError(f"{item!r} is not a known colormap name")
121+
122+
def __iter__(self):
123+
return iter(self._cmaps)
124+
125+
def __len__(self):
126+
return len(self._cmaps)
127+
128+
def __str__(self):
129+
return ('ColormapRegistry; available colormaps:\n' +
130+
', '.join(f"'{name}'" for name in self))
131+
132+
def register(self, cmap, *, name=None, force=False):
133+
"""
134+
Register a new colormap.
135+
136+
The colormap name can then be used as a string argument to any ``cmap``
137+
parameter in Matplotlib. It is also available in `.pyplot.get_cmap`.
138+
139+
The colormap registry stores a copy of the given colormap, so that
140+
future changes to the original colormap instance do not affect the
141+
registered colormap. Think of this as the registry taking a snapshot
142+
of the colormap at registration.
143+
144+
Parameters
145+
----------
146+
cmap : matplotlib.colors.Colormap
147+
The colormap to register.
148+
149+
name : str, optional
150+
The name for the colormap. If not given, the
151+
:attr:`~.Colormap.name` attribute of *cmap* is used.
152+
153+
force: bool, default: False
154+
155+
"""
156+
name_ = name or cmap.name
157+
if name_ in self and not force:
158+
raise ValueError(
159+
f'A colormap named "{name}" is already registered.')
160+
register_cmap(name, cmap.copy())
161+
162+
94163
_cmap_registry = _gen_cmap_registry()
95164
globals().update(_cmap_registry)
96165
# This is no longer considered public API
97166
cmap_d = _DeprecatedCmapDictWrapper(_cmap_registry)
98167
__builtin_cmaps = tuple(_cmap_registry)
99168

100-
# Continue with definitions ...
169+
# public acces to the colormaps should be via `matplotlib.colormaps`. For now,
170+
# we still create the registry here, but that should stay an implementation
171+
# detail.
172+
_colormaps = ColormapRegistry(_cmap_registry)
101173

102174

103175
def register_cmap(name=None, cmap=None, *, override_builtin=False):

0 commit comments

Comments
 (0)