1515 normalization.
1616"""
1717
18- from collections .abc import Mapping , MutableMapping
18+ from collections .abc import Mapping
1919
2020import numpy as np
2121from 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-
10159class 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
199195def 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
259233def 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
293261def 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
334298class ScalarMappable :
0 commit comments