Skip to content

Commit 07a46b2

Browse files
committed
MNT: Pending-deprecate setting colormap extremes
Per matplotlib#29141 we have the long-term plan to make colormaps immutable. As a result, the in-place modifications have to be removed. We take this particularly slow with at least two minor releases of pending deprecation and two further releases of actual deprecations. As it's quite a common concept and migrating away will take time.
1 parent f8400db commit 07a46b2

File tree

3 files changed

+41
-4
lines changed

3 files changed

+41
-4
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
In-place modifications of colormaps
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
Colormaps are planned to become immutable in the long term.
4+
5+
As a first step, in-place modifications of colormaps are now pending-deprecated.
6+
This affects the following methods of `.Colormap`:
7+
8+
- `.Colormap.set_bad` - use ``cmap.with_extremes(bad=...)`` instead
9+
- `.Colormap.set_under` - use ``cmap.with_extremes(under=...)`` instead
10+
- `.Colormap.set_over` - use ``cmap.with_extremes(over=...)`` instead
11+
- `.Colormap.set_extremes` - use ``cmap.with_extremes(...)`` instead
12+
13+
Use the respective `.Colormap.with_extremes` and appropriate keyword arguments
14+
instead which returns a copy of the colormap (available since matplotlib 3.4).
15+
Alternatively, if you create the colormap yourself, you can also pass the
16+
respective arguments to the constructor (available since matplotlib 3.11).

lib/matplotlib/colors.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,10 @@ def get_bad(self):
871871
self._ensure_inited()
872872
return np.array(self._lut[self._i_bad])
873873

874+
@_api.deprecated(
875+
"3.11",
876+
pending=True,
877+
alternative="cmap.with_extremes(bad=...) or Colormap(bad=...)")
874878
def set_bad(self, color='k', alpha=None):
875879
"""Set the color for masked values."""
876880
self._set_extremes(bad=(color, alpha))
@@ -880,6 +884,10 @@ def get_under(self):
880884
self._ensure_inited()
881885
return np.array(self._lut[self._i_under])
882886

887+
@_api.deprecated(
888+
"3.11",
889+
pending=True,
890+
alternative="cmap.with_extremes(under=...) or Colormap(under=...)")
883891
def set_under(self, color='k', alpha=None):
884892
"""Set the color for low out-of-range values."""
885893
self._set_extremes(under=(color, alpha))
@@ -889,10 +897,19 @@ def get_over(self):
889897
self._ensure_inited()
890898
return np.array(self._lut[self._i_over])
891899

900+
@_api.deprecated(
901+
"3.11",
902+
pending=True,
903+
alternative="cmap.with_extremes(over=...) or Colormap(over=...)")
892904
def set_over(self, color='k', alpha=None):
893905
"""Set the color for high out-of-range values."""
894906
self._set_extremes(over=(color, alpha))
895907

908+
@_api.deprecated(
909+
"3.11",
910+
pending=True,
911+
alternative="cmap.with_extremes(bad=..., under=..., over=...) or "
912+
"Colormap(bad=..., under=..., over=...)")
896913
def set_extremes(self, *, bad=None, under=None, over=None):
897914
"""
898915
Set the colors for masked (*bad*) values and, when ``norm.clip =

lib/matplotlib/tests/test_colors.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ def test_colormap_copy():
111111
with np.errstate(invalid='ignore'):
112112
ret1 = copied_cmap([-1, 0, .5, 1, np.nan, np.inf])
113113
cmap2 = copy.copy(copied_cmap)
114-
cmap2.set_bad('g')
114+
with pytest.warns(PendingDeprecationWarning):
115+
cmap2.set_bad('g')
115116
with np.errstate(invalid='ignore'):
116117
ret2 = copied_cmap([-1, 0, .5, 1, np.nan, np.inf])
117118
assert_array_equal(ret1, ret2)
@@ -121,7 +122,8 @@ def test_colormap_copy():
121122
with np.errstate(invalid='ignore'):
122123
ret1 = copied_cmap([-1, 0, .5, 1, np.nan, np.inf])
123124
cmap2 = copy.copy(copied_cmap)
124-
cmap2.set_bad('g')
125+
with pytest.warns(PendingDeprecationWarning):
126+
cmap2.set_bad('g')
125127
with np.errstate(invalid='ignore'):
126128
ret2 = copied_cmap([-1, 0, .5, 1, np.nan, np.inf])
127129
assert_array_equal(ret1, ret2)
@@ -135,7 +137,8 @@ def test_colormap_equals():
135137
# But the same data should be equal
136138
assert cm_copy == cmap
137139
# Change the copy
138-
cm_copy.set_bad('y')
140+
with pytest.warns(PendingDeprecationWarning):
141+
cm_copy.set_bad('y')
139142
assert cm_copy != cmap
140143
# Make sure we can compare different sizes without failure
141144
cm_copy._lut = cm_copy._lut[:10, :]
@@ -1535,7 +1538,8 @@ def test_get_under_over_bad():
15351538
def test_non_mutable_get_values(kind):
15361539
cmap = copy.copy(mpl.colormaps['viridis'])
15371540
init_value = getattr(cmap, f'get_{kind}')()
1538-
getattr(cmap, f'set_{kind}')('k')
1541+
with pytest.warns(PendingDeprecationWarning):
1542+
getattr(cmap, f'set_{kind}')('k')
15391543
black_value = getattr(cmap, f'get_{kind}')()
15401544
assert np.all(black_value == [0, 0, 0, 1])
15411545
assert not np.all(init_value == black_value)

0 commit comments

Comments
 (0)