1515 normalization.
1616<
7440
/code>"""
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,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 ().update (_colormaps )
197201
198202
199203def 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
259246def 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. This is undesired
269- because users could accidentally modify the global colormap.
270- From Matplotlib 3.6 on, this will return a copy instead.
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
293274def 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
334311class ScalarMappable :
0 commit comments