Skip to content

Commit 49ae5f5

Browse files
committed
Make colormap loading lazier
In most cases, 1 or possibly 2 colormaps are ever used in a plot, so loading all of them is a waste. Instead just record all the possible names, and load whichever is requested as necessary.
1 parent 01cfcb0 commit 49ae5f5

File tree

4 files changed

+83
-70
lines changed

4 files changed

+83
-70
lines changed

lib/matplotlib/_cm_bivar.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
# date: 2024-05-24
33

44
import numpy as np
5-
from matplotlib.colors import SegmentedBivarColormap
65

7-
BiPeak = np.array(
6+
BiPeak = (
87
[0.000, 0.674, 0.931, 0.000, 0.680, 0.922, 0.000, 0.685, 0.914, 0.000,
98
0.691, 0.906, 0.000, 0.696, 0.898, 0.000, 0.701, 0.890, 0.000, 0.706,
109
0.882, 0.000, 0.711, 0.875, 0.000, 0.715, 0.867, 0.000, 0.720, 0.860,
@@ -1273,9 +1272,10 @@
12731272
0.282, 0.946, 0.422, 0.263, 0.943, 0.417, 0.243, 0.939, 0.411, 0.223,
12741273
0.935, 0.405, 0.202, 0.931, 0.399, 0.181, 0.927, 0.393, 0.158, 0.923,
12751274
0.387, 0.134, 0.918, 0.381, 0.107,
1276-
]).reshape((65, 65, 3))
1275+
],
1276+
(65, 65, 3))
12771277

1278-
BiOrangeBlue = np.array(
1278+
BiOrangeBlue = (
12791279
[0.000, 0.000, 0.000, 0.000, 0.062, 0.125, 0.000, 0.125, 0.250, 0.000,
12801280
0.188, 0.375, 0.000, 0.250, 0.500, 0.000, 0.312, 0.625, 0.000, 0.375,
12811281
0.750, 0.000, 0.438, 0.875, 0.000, 0.500, 1.000, 0.125, 0.062, 0.000,
@@ -1301,12 +1301,18 @@
13011301
0.562, 0.125, 1.000, 0.625, 0.250, 1.000, 0.688, 0.375, 1.000, 0.750,
13021302
0.500, 1.000, 0.812, 0.625, 1.000, 0.875, 0.750, 1.000, 0.938, 0.875,
13031303
1.000, 1.000, 1.000,
1304-
]).reshape((9, 9, 3))
1304+
],
1305+
(9, 9, 3))
13051306

13061307
cmaps = {
1307-
"BiPeak": SegmentedBivarColormap(
1308-
BiPeak, 256, "square", (.5, .5), name="BiPeak"),
1309-
"BiOrangeBlue": SegmentedBivarColormap(
1310-
BiOrangeBlue, 256, "square", (0, 0), name="BiOrangeBlue"),
1311-
"BiCone": SegmentedBivarColormap(BiPeak, 256, "circle", (.5, .5), name="BiCone"),
1308+
"BiPeak": (*BiPeak, 256, "square", (.5, .5)),
1309+
"BiOrangeBlue": (*BiOrangeBlue, 256, "square", (0, 0)),
1310+
"BiCone": (*BiPeak, 256, "circle", (.5, .5)),
13121311
}
1312+
1313+
1314+
def cmap_init(name, cmap_spec):
1315+
from matplotlib.colors import SegmentedBivarColormap
1316+
data, shape, *args = cmap_spec
1317+
return SegmentedBivarColormap(np.array(data).reshape(shape), *args,
1318+
name=name)

lib/matplotlib/_cm_listed.py

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from .colors import ListedColormap
2-
31
_magma_data = [[0.001462, 0.000466, 0.013866],
42
[0.002258, 0.001295, 0.018331],
53
[0.003279, 0.002305, 0.023708],
@@ -2832,16 +2830,15 @@
28322830
[0.74458, 0.99141, 0.64748]]
28332831

28342832
cmaps = {
2835-
name: ListedColormap(data, name=name) for name, data in [
2836-
('magma', _magma_data),
2837-
('inferno', _inferno_data),
2838-
('plasma', _plasma_data),
2839-
('viridis', _viridis_data),
2840-
('cividis', _cividis_data),
2841-
('twilight', _twilight_data),
2842-
('twilight_shifted', _twilight_shifted_data),
2843-
('turbo', _turbo_data),
2844-
('berlin', _berlin_data),
2845-
('managua', _managua_data),
2846-
('vanimo', _vanimo_data),
2847-
]}
2833+
'magma': _magma_data,
2834+
'inferno': _inferno_data,
2835+
'plasma': _plasma_data,
2836+
'viridis': _viridis_data,
2837+
'cividis': _cividis_data,
2838+
'twilight': _twilight_data,
2839+
'twilight_shifted': _twilight_shifted_data,
2840+
'turbo': _turbo_data,
2841+
'berlin': _berlin_data,
2842+
'managua': _managua_data,
2843+
'vanimo': _vanimo_data,
2844+
}

lib/matplotlib/_cm_multivar.py

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# auto-generated by https://github.com/trygvrad/multivariate_colormaps
22
# date: 2024-05-28
33

4-
from .colors import LinearSegmentedColormap, MultivarColormap
54
import matplotlib as mpl
65
_LUTSIZE = mpl.rcParams['image.lut']
76

@@ -145,22 +144,17 @@
145144
[0.615, 0.175, 0.341],
146145
[0.649, 0.178, 0.355]]
147146

148-
cmaps = {
149-
name: LinearSegmentedColormap.from_list(name, data, _LUTSIZE) for name, data in [
150-
('2VarAddA0', _2VarAddA0_data),
151-
('2VarAddA1', _2VarAddA1_data),
152-
('2VarSubA0', _2VarSubA0_data),
153-
('2VarSubA1', _2VarSubA1_data),
154-
('3VarAddA0', _3VarAddA0_data),
155-
('3VarAddA1', _3VarAddA1_data),
156-
('3VarAddA2', _3VarAddA2_data),
157-
]}
158-
159147
cmap_families = {
160-
'2VarAddA': MultivarColormap([cmaps[f'2VarAddA{i}'] for i in range(2)],
161-
'sRGB_add', name='2VarAddA'),
162-
'2VarSubA': MultivarColormap([cmaps[f'2VarSubA{i}'] for i in range(2)],
163-
'sRGB_sub', name='2VarSubA'),
164-
'3VarAddA': MultivarColormap([cmaps[f'3VarAddA{i}'] for i in range(3)],
165-
'sRGB_add', name='3VarAddA'),
148+
'2VarAddA': ((_2VarAddA0_data, _2VarAddA1_data), 'sRGB_add'),
149+
'2VarSubA': ((_2VarSubA0_data, _2VarSubA1_data), 'sRGB_sub'),
150+
'3VarAddA': ((_3VarAddA0_data, _3VarAddA1_data, _3VarAddA2_data), 'sRGB_add'),
166151
}
152+
153+
154+
def cmap_init(name, cmap_spec):
155+
from .colors import LinearSegmentedColormap, MultivarColormap
156+
specs, combination_mode = cmap_spec
157+
return MultivarColormap(
158+
[LinearSegmentedColormap.from_list(f'{name}{i}', data, _LUTSIZE)
159+
for i, data in enumerate(specs)],
160+
combination_mode, name=name)

lib/matplotlib/cm.py

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,17 @@
1515
"""
1616

1717
from collections.abc import Mapping
18+
import functools
1819

1920
import matplotlib as mpl
2021
from matplotlib import _api, colors
2122
# TODO make this warn on access
2223
from matplotlib.colorizer import _ScalarMappable as ScalarMappable # noqa
2324
from matplotlib._cm import datad
2425
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
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

6673
class ColormapRegistry(Mapping):
@@ -87,12 +94,15 @@ 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
cmap = _api.check_getitem(self._cmaps, colormap=item, _error_cls=KeyError)
104+
if cmap is None:
105+
cmap = self._cmaps[item] = self._init_func(item, self._builtin_cmaps[item])
96106
return cmap.copy()
97107

98108
def __iter__(self):
@@ -233,12 +243,11 @@ def get_cmap(self, cmap):
233243
# public access to the colormaps should be via `matplotlib.colormaps`. For now,
234244
# we still create the registry here, but that should stay an implementation
235245
# detail.
236-
_colormaps = ColormapRegistry(_gen_cmap_registry())
237-
globals().update(_colormaps)
246+
_colormaps = ColormapRegistry(*_gen_cmap_registry())
238247

239-
_multivar_colormaps = ColormapRegistry(multivar_cmaps)
248+
_multivar_colormaps = ColormapRegistry(multivar_cmaps, _multivar_cmap_init)
240249

241-
_bivar_colormaps = ColormapRegistry(bivar_cmaps)
250+
_bivar_colormaps = ColormapRegistry(bivar_cmaps, _bivar_cmap_init)
242251

243252

244253
def _ensure_cmap(cmap):
@@ -268,3 +277,10 @@ def _ensure_cmap(cmap):
268277
if cmap_name not in _colormaps:
269278
_api.check_in_list(sorted(_colormaps), cmap=cmap_name)
270279
return mpl.colormaps[cmap_name]
280+
281+
282+
@functools.cache
283+
def __getattr__(name):
284+
if name in _colormaps._builtin_cmaps:
285+
return _colormaps[name]
286+
raise AttributeError(f"module 'matplotlib.cm' has no attribute {name!r}")

0 commit comments

Comments
 (0)