Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit6aca58e

Browse files
authored
Merge pull request#15127 from tacaswell/register_cmap_test
ENH/API: improvements to register_cmap
2 parents3560e84 +1a9dacf commit6aca58e

File tree

5 files changed

+140
-36
lines changed

5 files changed

+140
-36
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Raise or warn on registering a colormap twice
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
When using `matplotlib.cm.register_cmap` to register a user provided
5+
or third-party colormap it will now raise a `ValueError` if trying to
6+
over-write one of the built in colormaps and warn if trying to over
7+
write a user registered colormap. This may raise for user-registered
8+
colormaps in the future.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
Add ``cm.unregister_cmap`` function
3+
-----------------------------------
4+
5+
`.cm.unregister_cmap` allows users to remove a colormap that they
6+
have previously registered.

‎lib/matplotlib/cm.py

Lines changed: 77 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
frommatplotlibimport_api,colors,cbook
2525
frommatplotlib._cmimportdatad
2626
frommatplotlib._cm_listedimportcmapsascmaps_listed
27+
frommatplotlib.cbookimport_warn_external
2728

2829

2930
LUTSIZE=mpl.rcParams['image.lut']
@@ -95,37 +96,46 @@ def _warn_deprecated(self):
9596
locals().update(_cmap_registry)
9697
# This is no longer considered public API
9798
cmap_d=_DeprecatedCmapDictWrapper(_cmap_registry)
98-
99+
__builtin_cmaps=tuple(_cmap_registry)
99100

100101
# Continue with definitions ...
101102

102103

103-
defregister_cmap(name=None,cmap=None,data=None,lut=None):
104+
defregister_cmap(name=None,cmap=None,*,override_builtin=False):
104105
"""
105106
Add a colormap to the set recognized by :func:`get_cmap`.
106107
107-
It can be used in two ways::
108+
Register a new colormap to be accessed by name ::
109+
110+
LinearSegmentedColormap('swirly', data, lut)
111+
register_cmap(cmap=swirly_cmap)
108112
109-
register_cmap(name='swirly', cmap=swirly_cmap)
113+
Parameters
114+
----------
115+
name : str, optional
116+
The name that can be used in :func:`get_cmap` or :rc:`image.cmap`
110117
111-
register_cmap(name='choppy', data=choppydata, lut=128)
118+
If absent, the name will be the :attr:`~matplotlib.colors.Colormap.name`
119+
attribute of the *cmap*.
112120
113-
In the first case, *cmap* must be a :class:`matplotlib.colors.Colormap`
114-
instance. The *name* is optional; if absent, the name will
115-
be the :attr:`~matplotlib.colors.Colormap.name` attribute of the *cmap*.
121+
cmap :matplotlib.colors.Colormap
122+
Despite being the second argument and having a default value, this
123+
is a required argument.
116124
117-
The second case is deprecated. Here, the three arguments are passed to
118-
the :class:`~matplotlib.colors.LinearSegmentedColormap` initializer,
119-
and the resulting colormap is registered. Instead of this implicit
120-
colormap creation, create a `.LinearSegmentedColormap` and use the first
121-
case: ``register_cmap(cmap=LinearSegmentedColormap(name, data, lut))``.
125+
override_builtin : bool
126+
127+
Allow built-in colormaps to be overridden by a user-supplied
128+
colormap.
129+
130+
Please do not use this unless you are sure you need it.
122131
123132
Notes
124133
-----
125134
Registering a colormap stores a reference to the colormap object
126135
which can currently be modified and inadvertantly change the global
127136
colormap state. This behavior is deprecated and in Matplotlib 3.5
128137
the registered colormap will be immutable.
138+
129139
"""
130140
cbook._check_isinstance((str,None),name=name)
131141
ifnameisNone:
@@ -134,23 +144,21 @@ def register_cmap(name=None, cmap=None, data=None, lut=None):
134144
exceptAttributeErroraserr:
135145
raiseValueError("Arguments must include a name or a "
136146
"Colormap")fromerr
137-
ifisinstance(cmap,colors.Colormap):
138-
cmap._global=True
139-
_cmap_registry[name]=cmap
140-
return
141-
iflutisnotNoneordataisnotNone:
142-
cbook.warn_deprecated(
143-
"3.3",
144-
message="Passing raw data via parameters data and lut to "
145-
"register_cmap() is deprecated since %(since)s and will "
146-
"become an error %(removal)s. Instead use: register_cmap("
147-
"cmap=LinearSegmentedColormap(name, data, lut))")
148-
# For the remainder, let exceptions propagate.
149-
iflutisNone:
150-
lut=mpl.rcParams['image.lut']
151-
cmap=colors.LinearSegmentedColormap(name,data,lut)
147+
ifnamein_cmap_registry:
148+
ifnotoverride_builtinandnamein__builtin_cmaps:
149+
msg=f"Trying to re-register the builtin cmap{name!r}."
150+
raiseValueError(msg)
151+
else:
152+
msg=f"Trying to register the cmap{name!r} which already exists."
153+
_warn_external(msg)
154+
155+
ifnotisinstance(cmap,colors.Colormap):
156+
raiseValueError("You must pass a Colormap instance. "
157+
f"You passed{cmap} a{type(cmap)} object.")
158+
152159
cmap._global=True
153160
_cmap_registry[name]=cmap
161+
return
154162

155163

156164
defget_cmap(name=None,lut=None):
@@ -187,6 +195,47 @@ def get_cmap(name=None, lut=None):
187195
return_cmap_registry[name]._resample(lut)
188196

189197

198+
defunregister_cmap(name):
199+
"""
200+
Remove a colormap recognized by :func:`get_cmap`.
201+
202+
You may not remove built-in colormaps.
203+
204+
If the named colormap is not registered, returns with no error, raises
205+
if you try to de-register a default colormap.
206+
207+
.. warning ::
208+
209+
Colormap names are currently a shared namespace that may be used
210+
by multiple packages. Use `unregister_cmap` only if you know you
211+
have registered that name before. In particular, do not
212+
unregister just in case to clean the name before registering a
213+
new colormap.
214+
215+
Parameters
216+
----------
217+
name : str
218+
The name of the colormap to be un-registered
219+
220+
Returns
221+
-------
222+
ColorMap or None
223+
If the colormap was registered, return it if not return `None`
224+
225+
Raises
226+
------
227+
ValueError
228+
If you try to de-register a default built-in colormap.
229+
230+
"""
231+
ifnamenotin_cmap_registry:
232+
return
233+
ifnamein__builtin_cmaps:
234+
raiseValueError(f"cannot unregister{name!r} which is a builtin "
235+
"colormap.")
236+
return_cmap_registry.pop(name)
237+
238+
190239
classScalarMappable:
191240
"""
192241
A mixin class to map scalar data to RGBA.

‎lib/matplotlib/colors.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ def get_bad(self):
652652
"""Get the color for masked values."""
653653
ifnotself._isinit:
654654
self._init()
655-
returnself._lut[self._i_bad]
655+
returnnp.array(self._lut[self._i_bad])
656656

657657
defset_bad(self,color='k',alpha=None):
658658
"""Set the color for masked values."""
@@ -665,7 +665,7 @@ def get_under(self):
665665
"""Get the color for low out-of-range values."""
666666
ifnotself._isinit:
667667
self._init()
668-
returnself._lut[self._i_under]
668+
returnnp.array(self._lut[self._i_under])
669669

670670
defset_under(self,color='k',alpha=None):
671671
"""Set the color for low out-of-range values."""
@@ -678,7 +678,7 @@ def get_over(self):
678678
"""Get the color for high out-of-range values."""
679679
ifnotself._isinit:
680680
self._init()
681-
returnself._lut[self._i_over]
681+
returnnp.array(self._lut[self._i_over])
682682

683683
defset_over(self,color='k',alpha=None):
684684
"""Set the color for high out-of-range values."""

‎lib/matplotlib/tests/test_colors.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,44 @@ def test_resample():
6464

6565

6666
deftest_register_cmap():
67-
new_cm=copy.copy(plt.cm.viridis)
68-
cm.register_cmap('viridis2',new_cm)
69-
assertplt.get_cmap('viridis2')==new_cm
67+
new_cm=copy.copy(cm.get_cmap("viridis"))
68+
target="viridis2"
69+
cm.register_cmap(target,new_cm)
70+
assertplt.get_cmap(target)==new_cm
7071

7172
withpytest.raises(ValueError,
72-
match='Arguments must include a name or a Colormap'):
73+
match="Arguments must include a name or a Colormap"):
7374
cm.register_cmap()
7475

76+
withpytest.warns(UserWarning):
77+
cm.register_cmap(target,new_cm)
78+
79+
cm.unregister_cmap(target)
80+
withpytest.raises(ValueError,
81+
match=f'{target!r} is not a valid value for name;'):
82+
cm.get_cmap(target)
83+
# test that second time is error free
84+
cm.unregister_cmap(target)
85+
86+
withpytest.raises(ValueError,match="You must pass a Colormap instance."):
87+
cm.register_cmap('nome',cmap='not a cmap')
88+
89+
90+
deftest_double_register_builtin_cmap():
91+
name="viridis"
92+
match=f"Trying to re-register the builtin cmap{name!r}."
93+
withpytest.raises(ValueError,match=match):
94+
cm.register_cmap(name,cm.get_cmap(name))
95+
withpytest.warns(UserWarning):
96+
cm.register_cmap(name,cm.get_cmap(name),override_builtin=True)
97+
98+
99+
deftest_unregister_builtin_cmap():
100+
name="viridis"
101+
match=f'cannot unregister{name!r} which is a builtin colormap.'
102+
withpytest.raises(ValueError,match=match):
103+
cm.unregister_cmap(name)
104+
75105

76106
deftest_colormap_global_set_warn():
77107
new_cm=plt.get_cmap('viridis')
@@ -94,7 +124,8 @@ def test_colormap_global_set_warn():
94124
new_cm.set_under('k')
95125

96126
# Re-register the original
97-
plt.register_cmap(cmap=orig_cmap)
127+
withpytest.warns(UserWarning):
128+
plt.register_cmap(cmap=orig_cmap,override_builtin=True)
98129

99130

100131
deftest_colormap_dict_deprecate():
@@ -1187,6 +1218,16 @@ def test_get_under_over_bad():
11871218
assert_array_equal(cmap.get_bad(),cmap(np.nan))
11881219

11891220

1221+
@pytest.mark.parametrize('kind', ('over','under','bad'))
1222+
deftest_non_mutable_get_values(kind):
1223+
cmap=copy.copy(plt.get_cmap('viridis'))
1224+
init_value=getattr(cmap,f'get_{kind}')()
1225+
getattr(cmap,f'set_{kind}')('k')
1226+
black_value=getattr(cmap,f'get_{kind}')()
1227+
assertnp.all(black_value== [0,0,0,1])
1228+
assertnotnp.all(init_value==black_value)
1229+
1230+
11901231
deftest_colormap_alpha_array():
11911232
cmap=plt.get_cmap('viridis')
11921233
vals= [-1,0.5,2]# under, valid, over

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp