15
15
"""
16
16
17
17
from collections .abc import Mapping
18
+ import functools
18
19
19
20
import matplotlib as mpl
20
21
from matplotlib import _api , colors
21
22
# TODO make this warn on access
22
23
from matplotlib .colorizer import _ScalarMappable as ScalarMappable # noqa
23
24
from matplotlib ._cm import datad
24
25
from 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
27
29
28
30
29
31
_LUTSIZE = mpl .rcParams ['image.lut' ]
@@ -34,15 +36,6 @@ def _gen_cmap_registry():
34
36
Generate a dict mapping standard colormap names to standard colormaps, as
35
37
well as the reversed colormaps.
36
38
"""
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
-
46
39
# Register colormap aliases for gray and grey.
47
40
aliases = {
48
41
# alias -> original name
@@ -51,16 +44,30 @@ def _gen_cmap_registry():
51
44
'gist_yerg' : 'gist_yarg' ,
52
45
'Grays' : 'Greys' ,
53
46
}
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 )
58
69
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
64
71
65
72
66
73
class ColormapRegistry (Mapping ):
@@ -87,13 +94,18 @@ class ColormapRegistry(Mapping):
87
94
from matplotlib import colormaps
88
95
list(colormaps)
89
96
"""
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
93
101
94
102
def __getitem__ (self , item ):
95
103
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 ()
97
109
except KeyError :
98
110
raise KeyError (f"{ item !r} is not a known colormap name" ) from None
99
111
@@ -235,12 +247,11 @@ def get_cmap(self, cmap):
235
247
# public access to the colormaps should be via `matplotlib.colormaps`. For now,
236
248
# we still create the registry here, but that should stay an implementation
237
249
# detail.
238
- _colormaps = ColormapRegistry (_gen_cmap_registry ())
239
- globals ().update (_colormaps )
250
+ _colormaps = ColormapRegistry (* _gen_cmap_registry ())
240
251
241
- _multivar_colormaps = ColormapRegistry (multivar_cmaps )
252
+ _multivar_colormaps = ColormapRegistry (multivar_cmaps , _multivar_cmap_init )
242
253
243
- _bivar_colormaps = ColormapRegistry (bivar_cmaps )
254
+ _bivar_colormaps = ColormapRegistry (bivar_cmaps , _bivar_cmap_init )
244
255
245
256
246
257
# 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):
307
318
if cmap_name not in _colormaps :
308
319
_api .check_in_list (sorted (_colormaps ), cmap = cmap_name )
309
320
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