8000 MNT: Remove cmap_d colormap access · matplotlib/matplotlib@d009a4b · 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 d009a4b

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

File tree

6 files changed

+67
-156
lines changed

6 files changed

+67
-156
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/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: 56 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,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,60 @@ def register(self, cmap, *, name=None, force=False):
177136
registered name. True supports overwriting registered colormaps
178137
other than the builtin colormaps.
179138
"""
139+
_api.check_isinstance(colors.Colormap, cmap=cmap)
140+
180141
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())
142+
if name in self:
143+
if force:
144+
_api.warn_external(f"Trying to register the cmap {name!r} "
145+
"which already exists.")
146+
147+
else:
148+
raise ValueError(
149+
f"Trying to re-register the builtin cmap {name!r}."
150+
if name in self._builtin_cmaps else
151+
f'A colormap named "{name}" is already registered.')
152+
153+
self._cmaps[name] = cmap.copy()
185154

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

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

193188
# public access to the colormaps should be via `matplotlib.colormaps`. For now,
194189
# we still create the registry here, but that should stay an implementation
195190
# detail.
196-
_colormaps = ColormapRegistry(_cmap_registry)
191+
_colormaps = ColormapRegistry(_gen_cmap_registry())
192+
globals().update(_colormaps)
197193

198194

199195
def register_cmap(name=None, cmap=None, *, override_builtin=False):
@@ -223,14 +219,6 @@ def register_cmap(name=None, cmap=None, *, override_builtin=False):
223219
colormap.
224220
225221
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-
234222
"""
235223
_api.check_isinstance((str, None), name=name)
236224
if name is None:
@@ -239,21 +227,7 @@ def register_cmap(name=None, cmap=None, *, override_builtin=False):
239227
except AttributeError as err:
240228
raise ValueError("Arguments must include a name or a "
241229
"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
230+
_colormaps.register(cmap, name=name, force=override_builtin)
257231

258232

259233
def get_cmap(name=None, lut=None):
@@ -263,12 +237,6 @@ def get_cmap(name=None, lut=None):
263237
Colormaps added with :func:`register_cmap` take precedence over
264238
built-in colormaps.
265239
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-
272240
Parameters
273241
----------
274242
name : `matplotlib.colors.Colormap` or str or None, default: None
@@ -283,11 +251,11 @@ def get_cmap(name=None, lut=None):
283251
name = mpl.rcParams['image.cmap']
284252
if isinstance(name, colors.Colormap):
285253
return name
286-
_api.check_in_list(sorted(_cmap_registry), name=name)
254+
_api.check_in_list(sorted(_colormaps), name=name)
287255
if lut is None:
288-
return _cmap_registry[name]
256+
return _colormaps[name]
289257
else:
290-
return _cmap_registry[name]._resample(lut)
258+
return _colormaps[name]._resample(lut)
291259

292260

293261
def unregister_cmap(name):
@@ -321,14 +289,10 @@ def unregister_cmap(name):
321289
------
322290
ValueError
323291
If you try to de-register a default built-in colormap.
324-
325292
"""
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)
293+
cmap = _colormaps.get(name, None)
294+
_colormaps.unregister(name)
295+
return cmap
332296

333297

334298
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: 2 additions & 41 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,17 +75,14 @@ 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;'):
8481
cm.get_cmap(target)
8582
# test that second time is error free
8683
cm.unregister_cmap(target)
8784

88-
with pytest.raises(ValueError, match="You must pass a Colormap instance."):
85+
with pytest.raises(TypeError, match="'cmap' must be"):
8986
cm.register_cmap('nome', cmap='not a cmap')
9087

9188

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

lib/matplotlib/tests/test_pickle.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ def test_inset_and_secondary():
201201
pickle.loads(pickle.dumps(fig))
202202

203203

204-
@pytest.mark.parametrize("cmap", cm._cmap_registry.values())
204+
@pytest.mark.parametrize("cmap", cm._colormaps.values())
205205
def test_cmap(cmap):
206206
pickle.dumps(cmap)
207207

0 commit comments

Comments
 (0)
0