-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Expand file tree
/
Copy pathcm.py
More file actions
241 lines (187 loc) · 7.95 KB
/
cm.py
File metadata and controls
241 lines (187 loc) · 7.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
"""
Builtin colormaps, colormap handling utilities, and the `ScalarMappable` mixin.
.. seealso::
:doc:`/gallery/color/colormap_reference` for a list of builtin colormaps.
:ref:`colormap-manipulation` for examples of how to make
colormaps.
:ref:`colormaps` an in-depth discussion of choosing
colormaps.
:ref:`colormapnorms` for more details about data normalization.
"""
from collections.abc import Mapping
import matplotlib as mpl
from matplotlib import _api, colors
# TODO make this warn on access
from matplotlib.colorizer import _ScalarMappable as ScalarMappable # noqa
from matplotlib._cm import datad
from matplotlib._cm_listed import cmaps as cmaps_listed
from matplotlib._cm_multivar import cmap_families as multivar_cmaps
from matplotlib._cm_bivar import cmaps as bivar_cmaps
_LUTSIZE = mpl.rcParams['image.lut']
def _gen_cmap_registry():
"""
Generate a dict mapping standard colormap names to standard colormaps, as
well as the reversed colormaps.
"""
cmap_d = {**cmaps_listed}
for name, spec in datad.items():
cmap_d[name] = ( # Precache the cmaps at a fixed lutsize..
colors.LinearSegmentedColormap(name, spec, _LUTSIZE)
if 'red' in spec else
colors.ListedColormap(spec['listed'], name)
if 'listed' in spec else
colors.LinearSegmentedColormap.from_list(name, spec, _LUTSIZE))
# Register colormap aliases for gray and grey.
aliases = {
# alias -> original name
'grey': 'gray',
'gist_grey': 'gist_gray',
'gist_yerg': 'gist_yarg',
'Grays': 'Greys',
}
for alias, original_name in aliases.items():
cmap = cmap_d[original_name].copy()
cmap.name = alias
cmap_d[alias] = cmap
# Generate reversed cmaps.
for cmap in list(cmap_d.values()):
rmap = cmap.reversed()
cmap_d[rmap.name] = rmap
return cmap_d
class ColormapRegistry(Mapping):
r"""
Container for colormaps that are known to Matplotlib by name.
The universal registry instance is `matplotlib.colormaps`. There should be
no need for users to instantiate `.ColormapRegistry` themselves.
Read access uses a dict-like interface mapping names to `.Colormap`\s::
import matplotlib as mpl
cmap = mpl.colormaps['viridis']
Returned `.Colormap`\s are copies, so that their modification does not
change the global definition of the colormap.
Additional colormaps can be added via `.ColormapRegistry.register`::
mpl.colormaps.register(my_colormap)
To get a list of all registered colormaps, you can do::
from matplotlib import colormaps
list(colormaps)
"""
def __init__(self, cmaps):
self._cmaps = cmaps
self._builtin_cmaps = tuple(cmaps)
def __getitem__(self, item):
cmap = _api.getitem_checked(self._cmaps, colormap=item, _error_cls=KeyError)
return cmap.copy()
def __iter__(self):
return iter(self._cmaps)
def __len__(self):
return len(self._cmaps)
def __str__(self):
return ('ColormapRegistry; available colormaps:\n' +
', '.join(f"'{name}'" for name in self))
def __call__(self):
"""
Return a list of the registered colormap names.
This exists only for backward-compatibility in `.pyplot` which had a
``plt.colormaps()`` method. The recommended way to get this list is
now ``list(colormaps)``.
"""
return list(self)
def register(self, cmap, *, name=None, force=False):
"""
Register a new colormap.
The colormap name can then be used as a string argument to any ``cmap``
parameter in Matplotlib. It is also available in ``pyplot.get_cmap``.
The colormap registry stores a copy of the given colormap, so that
future changes to the original colormap instance do not affect the
registered colormap. Think of this as the registry taking a snapshot
of the colormap at registration.
Parameters
----------
cmap : matplotlib.colors.Colormap
The colormap to register.
name : str, optional
The name for the colormap. If not given, ``cmap.name`` is used.
force : bool, default: False
If False, a ValueError is raised if trying to overwrite an already
registered name. True supports overwriting registered colormaps
other than the builtin colormaps.
"""
_api.check_isinstance(colors.Colormap, cmap=cmap)
name = name or cmap.name
if name in self:
if not force:
# don't allow registering an already existing cmap
# unless explicitly asked to
raise ValueError(
f'A colormap named "{name}" is already registered.')
elif name in self._builtin_cmaps:
# We don't allow overriding a builtin.
raise ValueError("Re-registering the builtin cmap "
f"{name!r} is not allowed.")
# Warn that we are updating an already existing colormap
_api.warn_external(f"Overwriting the cmap {name!r} "
"that was already in the registry.")
self._cmaps[name] = cmap.copy()
# Someone may set the extremes of a builtin colormap and want to register it
# with a different name for future lookups. The object would still have the
# builtin name, so we should update it to the registered name
if self._cmaps[name].name != name:
self._cmaps[name].name = name
def unregister(self, name):
"""
Remove a colormap from the registry.
You cannot remove built-in colormaps.
If the named colormap is not registered, returns with no error, raises
if you try to de-register a default colormap.
.. warning::
Colormap names are currently a shared namespace that may be used
by multiple packages. Use `unregister` only if you know you
have registered that name before. In particular, do not
unregister just in case to clean the name before registering a
new colormap.
Parameters
----------
name : str
The name of the colormap to be removed.
Raises
------
ValueError
If you try to remove a default built-in colormap.
"""
if name in self._builtin_cmaps:
raise ValueError(f"cannot unregister {name!r} which is a builtin "
"colormap.")
self._cmaps.pop(name, None)
def get_cmap(self, cmap):
"""
Return a color map specified through *cmap*.
Parameters
----------
cmap : str or `~matplotlib.colors.Colormap` or None
- if a `.Colormap`, return it
- if a string, look it up in ``mpl.colormaps``
- if None, return the Colormap defined in :rc:`image.cmap`
Returns
-------
Colormap
"""
# get the default color map
if cmap is None:
return self[mpl.rcParams["image.cmap"]]
# if the user passed in a Colormap, simply return it
if isinstance(cmap, colors.Colormap):
return cmap
if isinstance(cmap, str):
_api.check_in_list(sorted(_colormaps), cmap=cmap)
# otherwise, it must be a string so look it up
return self[cmap]
raise TypeError(
'get_cmap expects None or an instance of a str or Colormap . ' +
f'you passed {cmap!r} of type {type(cmap)}'
)
# public access to the colormaps should be via `matplotlib.colormaps`. For now,
# we still create the registry here, but that should stay an implementation
# detail.
_colormaps = ColormapRegistry(_gen_cmap_registry())
globals().update(_colormaps)
_multivar_colormaps = ColormapRegistry(multivar_cmaps)
_bivar_colormaps = ColormapRegistry(bivar_cmaps)