1515"""
1616
1717from collections .abc import Mapping
18+ import functools
1819
1920import matplotlib as mpl
2021from matplotlib import _api , colors
2122# TODO make this warn on access
2223from matplotlib .colorizer import _ScalarMappable as ScalarMappable # noqa
2324from matplotlib ._cm import datad
2425from matplotlib ._cm_listed import cmaps as cmaps_listed
25- from matplotlib ._cm_multivar import cmap_families as multivar_cmaps
26- from matplotlib ._cm_bivar import cmaps as bivar_cmaps
26+ from matplotlib ._cm_multivar import (
27+ cmap_families as multivar_cmaps , cmap_init as _multivar_cmap_init )
28+ from matplotlib ._cm_bivar import cmaps as bivar_cmaps , cmap_init as _bivar_cmap_init
2729
2830
2931_LUTSIZE = mpl .rcParams ['image.lut' ]
@@ -34,15 +36,6 @@ def _gen_cmap_registry():
3436 Generate a dict mapping standard colormap names to standard colormaps, as
3537 well as the reversed colormaps.
3638 """
37- cmap_d = {** cmaps_listed }
38- for name , spec in datad .items ():
39- cmap_d [name ] = ( # Precache the cmaps at a fixed lutsize..
40- colors .LinearSegmentedColormap (name , spec , _LUTSIZE )
41- if 'red' in spec else
42- colors .ListedColormap (spec ['listed' ], name )
43- if 'listed' in spec else
44- colors .LinearSegmentedColormap .from_list (name , spec , _LUTSIZE ))
45-
4639 # Register colormap aliases for gray and grey.
4740 aliases = {
4841 # alias -> original name
@@ -51,16 +44,30 @@ def _gen_cmap_registry():
5144 'gist_yerg' : 'gist_yarg' ,
5245 'Grays' : 'Greys' ,
5346 }
54- for alias , original_name in aliases .items ():
55- cmap = cmap_d [original_name ].copy ()
56- cmap .name = alias
57- cmap_d [alias ] = cmap
47+ cmap_d = {** cmaps_listed , ** datad , ** aliases }
48+ # Reversed cmaps.
49+ for name in list (cmap_d .keys ()):
50+ cmap_d [f'{ name } _r' ] = name
51+
52+ def cmap_init (name , cmap_spec ):
53+ if name in datad :
54+ spec = cmap_spec
55+ return ( # Precache the cmaps at a fixed lutsize..
56+ colors .LinearSegmentedColormap (name , spec , _LUTSIZE )
57+ if 'red' in spec else
58+ colors .ListedColormap (spec ['listed' ], name )
59+ if 'listed' in spec else
60+ colors .LinearSegmentedColormap .from_list (name , spec , _LUTSIZE ))
61+ if name in aliases :
62+ cmap = cmap_init (cmap_spec , cmap_d [cmap_spec ]).copy ()
63+ cmap .name = name
64+ return cmap
65+ if name .endswith ('_r' ):
66+ # Generate reversed cmaps.
67+ return cmap_init (cmap_spec , cmap_d [cmap_spec ]).reversed ()
68+ return colors .ListedColormap (cmap_spec , name = name )
5869
59- # Generate reversed cmaps.
60- for cmap in list (cmap_d .values ()):
61- rmap = cmap .reversed ()
62- cmap_d [rmap .name ] = rmap
63- return cmap_d
70+ return cmap_d , cmap_init
6471
6572
6673class ColormapRegistry (Mapping ):
@@ -87,13 +94,18 @@ class ColormapRegistry(Mapping):
8794 from matplotlib import colormaps
8895 list(colormaps)
8996 """
90- def __init__ (self , cmaps ):
91- self ._cmaps = cmaps
92- self ._builtin_cmaps = tuple (cmaps )
97+ def __init__ (self , cmaps , init_func ):
98+ self ._cmaps = {name : None for name in cmaps }
99+ self ._init_func = init_func
100+ self ._builtin_cmaps = cmaps
93101
94102 def __getitem__ (self , item ):
95103 try :
96- return self ._cmaps [item ].copy ()
104+ cmap = self ._cmaps [item ]
105+ if cmap is None :
106+ cmap = self ._cmaps [item ] = self ._init_func (item ,
107+ self ._builtin_cmaps [item ])
108+ return cmap .copy ()
97109 except KeyError :
98110 raise KeyError (f"{ item !r} is not a known colormap name" ) from None
99111
@@ -235,12 +247,11 @@ def get_cmap(self, cmap):
235247# public access to the colormaps should be via `matplotlib.colormaps`. For now,
236248# we still create the registry here, but that should stay an implementation
237249# detail.
238- _colormaps = ColormapRegistry (_gen_cmap_registry ())
239- globals ().update (_colormaps )
250+ _colormaps = ColormapRegistry (* _gen_cmap_registry ())
240251
241- _multivar_colormaps = ColormapRegistry (multivar_cmaps )
252+ _multivar_colormaps = ColormapRegistry (multivar_cmaps , _multivar_cmap_init )
242253
243- _bivar_colormaps = ColormapRegistry (bivar_cmaps )
254+ _bivar_colormaps = ColormapRegistry (bivar_cmaps , _bivar_cmap_init )
244255
245256
246257# This is an exact copy of pyplot.get_cmap(). It was removed in 3.9, but apparently
@@ -307,3 +318,10 @@ def _ensure_cmap(cmap):
307318 if cmap_name not in _colormaps :
308319 _api .check_in_list (sorted (_colormaps ), cmap = cmap_name )
309320 return mpl .colormaps [cmap_name ]
321+
322+
323+ @functools .cache
324+ def __getattr__ (name ):
325+ if name in _colormaps ._builtin_cmaps :
326+ return _colormaps [name ]
327+ raise AttributeError (f"module 'matplotlib.cm' has no attribute { name !r} " )
0 commit comments