8000 MNT: Remove cmap_d colormap access · matplotlib/matplotlib@53aa1ab · GitHub
[go: up one dir, main page]

Skip to content
Sign in

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 53aa1ab

Browse files
committed
MNT: Remove cmap_d colormap access
1 parent 80073f6 commit 53aa1ab

File tree

6 files changed

+82
-158
lines changed

6 files changed

+82
-158
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
``cmap_d`` removal
2+
~~~~~~~~~~~~~~~~~~
3+
4+
The deprecated ``matplotlib.cm.cmap_d`` access to global colormaps
5+
has been removed. Use the `.ColormapRegistry` instead, which is accessible
6+
via ``matplotlib.colormaps`` and ``pyplot.colormaps``.

lib/matplotlib/backends/qt_editor/figureoptions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,10 @@ def prepare_data(d, init):
135135
continue
136136
labeled_mappables.append((label, mappable))
137137
mappables = []
138-
cmaps = [(cmap, name) for name, cmap in sorted(cm._cmap_registry.items())]
138+
cmaps = [(cmap, name) for name, cmap in sorted(cm._colormaps.items())]
139139
for label, mappable in labeled_mappables:
140140
cmap = mappable.get_cmap()
141-
if cmap not in cm._cmap_registry.values():
141+
if cmap not in cm._colormaps.values():
142142
cmaps = [(cmap, cmap.name), *cmaps]
143143
low, high = mappable.get_clim()
144144
mappabledata = [

lib/matplotlib/cm.py

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

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

2020
import numpy as np
2121
from numpy import ma
@@ -52,52 +52,10 @@ def _gen_cmap_registry():
5252
# Generate reversed cmaps.
5353
for cmap in list(cmap_d.values()):
5454
rmap = cmap.reversed()
55-
cmap._global = True
56-
rmap._global = True
5755
cmap_d[rmap.name] = rmap
5856
return cmap_d
5957

6058

61-
class _DeprecatedCmapDictWrapper(MutableMapping):
62-
"""Dictionary mapping for deprecated _cmap_d access."""
63-
64-
def __init__(self, cmap_registry):
65-
self._cmap_registry = cmap_registry
66-
67-
def __delitem__(self, key):
68-
self._warn_deprecated()
69-
self._cmap_registry.__delitem__(key)
70-
71-
def __getitem__(self, key):
72-
self._warn_deprecated()
73-
return self._cmap_registry.__getitem__(key)
74-
75-
def __iter__(self):
76-
self._warn_deprecated()
77-
return self._cmap_registry.__iter__()
78-
79-
def __len__(self):
80-
self._warn_deprecated()
81-
return self._cmap_registry.__len__()
82-
83-
def __setitem__(self, key, val):
84-
self._warn_deprecated()
85-
self._cmap_registry.__setitem__(key, val)
86-
87-
def get(self, key, default=None):
88-
self._warn_deprecated()
89-
return self._cmap_registry.get(key, default)
90-
91-
def _warn_deprecated(self):
92-
_api.warn_deprecated(
93-
"3.3",
94-
message="The global colormaps dictionary is no longer "
95-
"considered public API.",
96-
alternative="Please use register_cmap() and get_cmap() to "
97-
"access the contents of the dictionary."
98-
)
99-
100-
10159
class ColormapRegistry(Mapping):
10260
r"""
10361
Container for colormaps that are known to Matplotlib by name.
@@ -125,6 +83,9 @@ class ColormapRegistry(Mapping):
12583
"""
12684
def __init__(self, cmaps):
12785
self._cmaps = cmaps
86+
self._builtin_cmaps = tuple(cmaps)
87+
# A shim to allow register_cmap() to force an override
88+
self._allow_override_builtin = False
12889

12990
def __getitem__(self, item):
13091
try:
@@ -177,23 +138,66 @@ def register(self, cmap, *, name=None, force=False):
177138
registered name. True supports overwriting registered colormaps
178139
other than the builtin colormaps.
179140
"""
141+
_api.check_isinstance(colors.Colormap, cmap=cmap)
142+
180143
name = name or cmap.name
181-
if name in self and not force:
182-
raise ValueError(
183-
f'A colormap named "{name}" is already registered.')
184-
register_cmap(name, cmap.copy())
144+
if name in self:
145+
if not force:
146+
# don't allow registering an already existing cmap
147+
# unless explicitly asked to
148+
raise ValueError(
149+
f'A colormap named "{name}" is already registered.')
150+
elif (name in self._builtin_cmaps
151+
and not self._allow_override_builtin):
152+
# We don't allow overriding a builtin unless privately
153+
# coming from register_cmap()
154+
raise ValueError("Re-registering the builtin cmap "
155+
f"{name!r} is not allowed.")
156+
157+
# Warn that we are updating an already exisiting colormap
158+
_api.warn_external(f"Overwriting the cmap {name!r} "
159+
"that was already in the registry.")
160+
161+
self._cmaps[name] = cmap.copy()
185162

163+
def unregister(self, name):
164+
"""
165+
Remove a colormap from the registry.
166+
167+
You cannot remove built-in colormaps.
168+
169+
If the named colormap is not registered, returns with no error, raises
170+
if you try to de-register a default colormap.
171+
172+
.. warning::
173+
174+
Colormap names are currently a shared namespace that may be used
175+
by multiple packages. Use `unregister` only if you know you
176+
have registered that name before. In particular, do not
177+
unregister just in case to clean the name before registering a
178+
new colormap.
179+
180+
Parameters
181+
----------
182+
name : str
183+
The name of the colormap to be removed.
184+
185+
Raises
186+
------
187+
ValueError
188+
If you try to remove a default built-in colormap.
189+
"""
190+
if name in self._builtin_cmaps:
191+
raise ValueError(f"cannot unregister {name!r} which is a builtin "
192+
"colormap.")
193+
self._cmaps.pop(name, None)
186194

187-
_cmap_registry = _gen_cmap_registry()
188-
globals().update(_cmap_registry)
189-
# This is no longer considered public API
190-
cmap_d = _DeprecatedCmapDictWrapper(_cmap_registry)
191-
__builtin_cmaps = tuple(_cmap_registry)
192195

193196
# public access to the colormaps should be via `matplotlib.colormaps`. For now,
194197
# we still create the registry here, but that should stay an implementation
195198
# detail.
196-
_colormaps = ColormapRegistry(_cmap_registry)
199+
_colormaps = ColormapRegistry(_gen_cmap_registry())
200+
globals F438 ().update(_colormaps)
197201

198202

199203
def register_cmap(name=None, cmap=None, *, override_builtin=False):
@@ -223,14 +227,6 @@ def register_cmap(name=None, cmap=None, *, override_builtin=False):
223227
colormap.
224228
225229
Please do not use this unless you are sure you need it.
226-
227-
Notes
228-
-----
229-
Registering a colormap stores a reference to the colormap object
230-
which can currently be modified and inadvertently change the global
231-
colormap state. This behavior is deprecated and in Matplotlib 3.5
232-
the registered colormap will be immutable.
233-
234230
"""
235231
_api.check_isinstance((str, None), name=name)
236232
if name is None:
@@ -239,21 +235,12 @@ def register_cmap(name=None, cmap=None, *, override_builtin=False):
239235
except AttributeError as err:
240236
raise ValueError("Arguments must include a name or a "
241237
"Colormap") from err
242-
if name in _cmap_registry:
243-
if not override_builtin and name in __builtin_cmaps:
244-
msg = f"Trying to re-register the builtin cmap {name!r}."
245-
raise ValueError(msg)
246-
else:
247-
msg = f"Trying to register the cmap {name!r} which already exists."
248-
_api.warn_external(msg)
249-
250-
if not isinstance(cmap, colors.Colormap):
251-
raise ValueError("You must pass a Colormap instance. "
252-
f"You passed {cmap} a {type(cmap)} object.")
253-
254-
cmap._global = True
255-
_cmap_registry[name] = cmap
256-
return
238+
# override_builtin is allowed here for backward compatbility
239+
# this is just a shim to enable that to work privately in
240+
# the global ColormapRegistry
241+
_colormaps._allow_override_builtin = override_builtin
242+
_colormaps.register(cmap, name=name, force=override_builtin)
243+
_colormaps._allow_override_builtin = False
257244

258245

259246
def get_cmap(name=None, lut=None):
@@ -263,12 +250,6 @@ def get_cmap(name=None, lut=None):
263250
Colormaps added with :func:`register_cmap` take precedence over
264251
built-in colormaps.
265252
266-
Notes
267-
-----
268-
Currently, this returns the global colormap object, which is deprecated.
269-
In Matplotlib 3.5, you will no longer be able to modify the global
270-
colormaps in-place.
271-
272253
Parameters
273254
----------
274255
name : `matplotlib.colors.Colormap` or str or None, default: None
@@ -283,11 +264,11 @@ def get_cmap(name=None, lut=None):
283264
name = mpl.rcParams['image.cmap']
284265
if isinstance(name, colors.Colormap):
285266
return name
286-
_api.check_in_list(sorted(_cmap_registry), name=name)
267+
_api.check_in_list(sorted(_colormaps), name=name)
287268
if lut is None:
288-
return _cmap_registry[name]
269+
return _colormaps[name]
289270
else:
290-
return _cmap_registry[name]._resample(lut)
271+
return _colormaps[name]._resample(lut)
291272

292273

293274
def unregister_cmap(name):
@@ -321,14 +302,10 @@ def unregister_cmap(name):
321302
------
322303
ValueError
323304
If you try to de-register a default built-in colormap.
324-
325305
"""
326-
if name not in _cmap_registry:
327-
return
328-
if name in __builtin_cmaps:
329-
raise ValueError(f"cannot unregister {name!r} which is a builtin "
330-
"colormap.")
331-
return _cmap_registry.pop(name)
306+
cmap = _colormaps.get(name, None)
307+
_colormaps.unregister(name)
308+
return cmap
332309

333310

334311
class ScalarMappable:

lib/matplotlib/colors.py

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141

4242
import base64
4343
from collections.abc import Sized, Sequence
44-
import copy
4544
import functools
4645
import inspect
4746
import io
@@ -534,20 +533,6 @@ def _create_lookup_table(N, data, gamma=1.0):
534533
return np.clip(lut, 0.0, 1.0)
535534

536535

537-
def _warn_if_global_cmap_modified(cmap):
538-
if getattr(cmap, '_global', False):
539-
_api.warn_deprecated(
540-
"3.3",
541-
removal="3.6",
542-
message="You are modifying the state of a globally registered "
543-
"colormap. This has been deprecated since %(since)s and "
544-
"%(removal)s, you will not be able to modify a "
545-
"registered colormap in-place. To remove this warning, "
546-
"you can make a copy of the colormap first. "
547-
f'cmap = mpl.cm.get_cmap("{cmap.name}").copy()'
548-
)
549-
550-
551536
class Colormap:
552537
"""
553538
Baseclass for all scalar to RGBA mappings.
@@ -664,7 +649,6 @@ def __copy__(self):
664649
cmapobject.__dict__.update(self.__dict__)
665650
if self._isinit:
666651
cmapobject._lut = np.copy(self._lut)
667-
cmapobject._global = False
668652
return cmapobject
669653

670654
def __eq__(self, other):
@@ -686,7 +670,6 @@ def get_bad(self):
686670

687671
def set_bad(self, color='k', alpha=None):
688672
"""Set the color for masked values."""
689-
_warn_if_global_cmap_modified(self)
690673
self._rgba_bad = to_rgba(color, alpha)
691674
if self._isinit:
692675
self._set_extremes()
@@ -699,7 +682,6 @@ def get_under(self):
699682

700683
def set_under(self, color='k', alpha=None):
701684
"""Set the color for low out-of-range values."""
702-
_warn_if_global_cmap_modified(self)
703685
self._rgba_under = to_rgba(color, alpha)
704686
if self._isinit:
705687
self._set_extremes()
@@ -712,7 +694,6 @@ def get_over(self):
712694

713695
def set_over(self, color='k', alpha=None):
714696
"""Set the color for high out-of-range values."""
715-
_warn_if_global_cmap_modified(self)
716697
self._rgba_over = to_rgba(color, alpha)
717698
if self._isinit:
718699
self._set_extremes()
@@ -735,7 +716,7 @@ def with_extremes(self, *, bad=None, under=None, over=None):
735716
values and, when ``norm.clip = False``, low (*under*) and high (*over*)
736717
out-of-range values, have been set accordingly.
737718
"""
738-
new_cm = copy.copy(self)
719+
new_cm = self.copy()
739720
new_cm.set_extremes(bad=bad, under=under, over=over)
740721
return new_cm
741722

0 commit comments

Comments
 (0)
0