15
15
normalization.
16
16
"""
17
17
18
- from collections .abc import Mapping , MutableMapping
18
+ from collections .abc import Mapping
19
19
20
20
import numpy as np
21
21
from numpy import ma
@@ -52,52 +52,10 @@ def _gen_cmap_registry():
52
52
# Generate reversed cmaps.
53
53
for cmap in list (cmap_d .values ()):
54
54
rmap = cmap .reversed ()
55
- cmap ._global = True
56
- rmap ._global = True
57
55
cmap_d [rmap .name ] = rmap
58
56
return cmap_d
59
57
60
58
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
-
101
59
class ColormapRegistry (Mapping ):
102
60
r"""
103
61
Container for colormaps that are known to Matplotlib by name.
@@ -125,6 +83,9 @@ class ColormapRegistry(Mapping):
125
83
"""
126
84
def __init__ (self , cmaps ):
127
85
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
128
89
129
90
def __getitem__ (self , item ):
130
91
try :
@@ -177,23 +138,66 @@ def register(self, cmap, *, name=None, force=False):
177
138
registered name. True supports overwriting registered colormaps
178
139
other than the builtin colormaps.
179
140
"""
141
+ _api .check_isinstance (colors .Colormap , cmap = cmap )
142
+
180
143
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 ()
185
162
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 )
186
194
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 )
192
195
193
196
# public access to the colormaps should be via `matplotlib.colormaps`. For now,
194
197
# we still create the registry here, but that should stay an implementation
195
198
# detail.
196
- _colormaps = ColormapRegistry (_cmap_registry )
199
+ _colormaps = ColormapRegistry (_gen_cmap_registry ())
200
+ globals
F438
().update (_colormaps )
197
201
198
202
199
203
def register_cmap (name = None , cmap = None , * , override_builtin = False ):
@@ -223,14 +227,6 @@ def register_cmap(name=None, cmap=None, *, override_builtin=False):
223
227
colormap.
224
228
225
229
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
-
234
230
"""
235
231
_api .check_isinstance ((str , None ), name = name )
236
232
if name is None :
@@ -239,21 +235,12 @@ def register_cmap(name=None, cmap=None, *, override_builtin=False):
239
235
except AttributeError as err :
240
236
raise ValueError ("Arguments must include a name or a "
241
237
"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
257
244
258
245
259
246
def get_cmap (name = None , lut = None ):
@@ -263,12 +250,6 @@ def get_cmap(name=None, lut=None):
263
250
Colormaps added with :func:`register_cmap` take precedence over
264
251
built-in colormaps.
265
252
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
-
272
253
Parameters
273
254
----------
274
255
name : `matplotlib.colors.Colormap` or str or None, default: None
@@ -283,11 +264,11 @@ def get_cmap(name=None, lut=None):
283
264
name = mpl .rcParams ['image.cmap' ]
284
265
if isinstance (name , colors .Colormap ):
285
266
return name
286
- _api .check_in_list (sorted (_cmap_registry ), name = name )
267
+ _api .check_in_list (sorted (_colormaps ), name = name )
287
268
if lut is None :
288
- return _cmap_registry [name ]
269
+ return _colormaps [name ]
289
270
else :
290
- return _cmap_registry [name ]._resample (lut )
271
+ return _colormaps [name ]._resample (lut )
291
272
292
273
293
274
def unregister_cmap (name ):
@@ -321,14 +302,10 @@ def unregister_cmap(name):
321
302
------
322
303
ValueError
323
304
If you try to de-register a default built-in colormap.
324
-
325
305
"""
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
332
309
333
310
334
311
class ScalarMappable :