Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fce605e

Browse files
committed
MNT: Remove cmap_d colormap access
1 parent 075067c commit fce605e

File tree

4 files changed

+65
-148
lines changed

4 files changed

+65
-148
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
``cmap_d`` removal
2+
~~~~~~~~~~~~~~~~~~
3+
4+
The deprecated ``matplotlib.cm.cmap_d`` access to global colormaps
5+
has been removed.

lib/matplotlib/cm.py

Lines changed: 58 additions & 88 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,7 @@ class ColormapRegistry(Mapping):
12583
"""
12684
def __init__(self, cmaps):
12785
self._cmaps = cmaps
86+
self._builtin_cmaps = tuple(cmaps)
12887

12988
def __getitem__(self, item):
13089
try:
@@ -177,23 +136,67 @@ def register(self, cmap, *, name=None, force=False):
177136
registered name. True supports overwriting registered colormaps
178137
other than the builtin colormaps.
179138
"""
139+
if not isinstance(cmap, colors.Colormap):
140+
raise ValueError("You must pass a Colormap instance. "
141+
f"You passed {cmap} a {type(cmap)} object.")
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 and name in self._builtin_cmaps:
146+
msg = f"Trying to re-register the builtin cmap {name!r}."
147+
raise ValueError(msg)
148+
elif not force:
149+
raise ValueError(
150+
f'A colormap named "{name}" is already registered.')
151+
else:
152+
_api.warn_external(f"Trying to register the cmap {name!r} "
153+
"which already exists.")
185154

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

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)
192194

193195
# public access to the colormaps should be via `matplotlib.colormaps`. For now,
194196
# we still create the registry here, but that should stay an implementation
195197
# detail.
196-
_colormaps = ColormapRegistry(_cmap_registry)
198+
_colormaps = _cmap_registry = ColormapRegistry(_gen_cmap_registry())
199+
globals().update(_cmap_registry)
197200

198201

199202
def register_cmap(name=None, cmap=None, *, override_builtin=False):
@@ -223,14 +226,6 @@ def register_cmap(name=None, cmap=None, *, override_builtin=False):
223226
colormap.
224227
225228
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-
234229
"""
235230
_api.check_isinstance((str, None), name=name)
236231
if name is None:
@@ -239,21 +234,7 @@ def register_cmap(name=None, cmap=None, *, override_builtin=False):
239234
except AttributeError as err:
240235
raise ValueError("Arguments must include a name or a "
241236
"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
237+
_cmap_registry.register(cmap, name=name, force=override_builtin)
257238

258239

259240
def get_cmap(name=None, lut=None):
@@ -263,12 +244,6 @@ def get_cmap(name=None, lut=None):
263244
Colormaps added with :func:`register_cmap` take precedence over
264245
built-in colormaps.
265246
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-
272247
Parameters
273248
----------
274249
name : `matplotlib.colors.Colormap` or str or None, default: None
@@ -323,12 +298,7 @@ def unregister_cmap(name):
323298
If you try to de-register a default built-in colormap.
324299
325300
"""
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)
301+
return _cmap_registry.unregister(name)
332302

333303

334304
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

lib/matplotlib/tests/test_colors.py

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def test_resample():
6666

6767

6868
def test_register_cmap():
69-
new_cm = copy.copy(cm.get_cmap("viridis"))
69+
new_cm = cm.get_cmap("viridis")
7070
target = "viridis2"
7171
cm.register_cmap(target, new_cm)
7272
assert plt.get_cmap(target) == new_cm
@@ -75,9 +75,6 @@ def test_register_cmap():
7575
match="Arguments must include a name or a Colormap"):
7676
cm.register_cmap()
7777

78-
with pytest.warns(UserWarning):
79-
cm.register_cmap(target, new_cm)
80-
8178
cm.unregister_cmap(target)
8279
with pytest.raises(ValueError,
8380
match=f'{target!r} is not a valid value for name;'):
@@ -105,42 +102,6 @@ def test_unregister_builtin_cmap():
105102
cm.unregister_cmap(name)
106103

107104

108-
def test_colormap_global_set_warn():
109-
new_cm = plt.get_cmap('viridis')
110-
# Store the old value so we don't override the state later on.
111-
orig_cmap = copy.copy(new_cm)
112-
with pytest.warns(cbook.MatplotlibDeprecationWarning,
113-
match="You are modifying the state of a globally"):
114-
# This should warn now because we've modified the global state
115-
new_cm.set_under('k')
116-
117-
# This shouldn't warn because it is a copy
118-
copy.copy(new_cm).set_under('b')
119-
120-
# Test that registering and then modifying warns
121-
plt.register_cmap(name='test_cm', cmap=copy.copy(orig_cmap))
122-
new_cm = plt.get_cmap('test_cm')
123-
with pytest.warns(cbook.MatplotlibDeprecationWarning,
124-
match="You are modifying the state of a globally"):
125-
# This should warn now because we've modified the global state
126-
new_cm.set_under('k')
127-
128-
# Re-register the original
129-
with pytest.warns(UserWarning):
130-
plt.register_cmap(cmap=orig_cmap, override_builtin=True)
131-
132-
133-
def test_colormap_dict_deprecate():
134-
# Make sure we warn on get and set access into cmap_d
135-
with pytest.warns(cbook.MatplotlibDeprecationWarning,
136-
match="The global colormaps dictionary is no longer"):
137-
cmap = plt.cm.cmap_d['viridis']
138-
139-
with pytest.warns(cbook.MatplotlibDeprecationWarning,
140-
match="The global colormaps dictionary is no longer"):
141-
plt.cm.cmap_d['test'] = cmap
142-
143-
144105
def test_colormap_copy():
145106
cmap = plt.cm.Reds
146107
copied_cmap = copy.copy(cmap)

0 commit comments

Comments
 (0)