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

Appearance settings

Commit 2fa9151

Browse filesBrowse files
timhoffmrcomer
andauthored
Deprecate ListedColormap(..., N=...) parameter (#29135)
* Deprecate ListedColormap(..., N=...) parameter Truncating or repeating the given colors to a specific value of N is not within the scope of colormaps. Instead, users should create an appropriate color list themselves and feed that to ListedColormap. Also the current behavior can be surprising: It may well be that a given N was intended to truncate, but depending on the list, it could repeat. Repeated colors in a colormap are dangerous / often not intentended because they create an ambiguity in the color -> value mapping. * Update lib/matplotlib/colors.py Co-authored-by: Ruth Comer <10599679+rcomer@users.noreply.github.com> --------- Co-authored-by: Ruth Comer <10599679+rcomer@users.noreply.github.com>
1 parent 72301c7 commit 2fa9151
Copy full SHA for 2fa9151

File tree

Expand file treeCollapse file tree

7 files changed

+66
-10
lines changed
Filter options
Expand file treeCollapse file tree

7 files changed

+66
-10
lines changed
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Parameter ``ListedColormap(..., N=...)``
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
Passing the parameter *N* to `.ListedColormap` is deprecated.
5+
Please preprocess the list colors yourself if needed.

‎lib/matplotlib/cbook.py

Copy file name to clipboardExpand all lines: lib/matplotlib/cbook.py
+20Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1739,6 +1739,26 @@ def sanitize_sequence(data):
17391739
else data)
17401740

17411741

1742+
def _resize_sequence(seq, N):
1743+
"""
1744+
Trim the given sequence to exactly N elements.
1745+
1746+
If there are more elements in the sequence, cut it.
1747+
If there are less elements in the sequence, repeat them.
1748+
1749+
Implementation detail: We maintain type stability for the output for
1750+
N <= len(seq). We simply return a list for N > len(seq); this was good
1751+
enough for the present use cases but is not a fixed design decision.
1752+
"""
1753+
num_elements = len(seq)
1754+
if N == num_elements:
1755+
return seq
1756+
elif N < num_elements:
1757+
return seq[:N]
1758+
else:
1759+
return list(itertools.islice(itertools.cycle(seq), N))
1760+
1761+
17421762
def normalize_kwargs(kw, alias_mapping=None):
17431763
"""
17441764
Helper function to normalize kwarg inputs.

‎lib/matplotlib/cbook.pyi

Copy file name to clipboardExpand all lines: lib/matplotlib/cbook.pyi
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ from typing import (
1414
Generic,
1515
IO,
1616
Literal,
17+
Sequence,
1718
TypeVar,
1819
overload,
1920
)
@@ -143,6 +144,7 @@ STEP_LOOKUP_MAP: dict[str, Callable]
143144
def index_of(y: float | ArrayLike) -> tuple[np.ndarray, np.ndarray]: ...
144145
def safe_first_element(obj: Collection[_T]) -> _T: ...
145146
def sanitize_sequence(data): ...
147+
def _resize_sequence(seq: Sequence, N: int) -> Sequence: ...
146148
def normalize_kwargs(
147149
kw: dict[str, Any],
148150
alias_mapping: dict[str, list[str]] | type[Artist] | Artist | None = ...,

‎lib/matplotlib/colors.py

Copy file name to clipboardExpand all lines: lib/matplotlib/colors.py
+10-3Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,13 @@ class ListedColormap(Colormap):
11901190
11911191
the list will be extended by repetition.
11921192
"""
1193+
1194+
@_api.delete_parameter(
1195+
"3.11", "N",
1196+
message="Passing 'N' to ListedColormap is deprecated since %(since)s "
1197+
"and will be removed in %(removal)s. Please ensure the list "
1198+
"of passed colors is the required length instead."
1199+
)
11931200
def __init__(self, colors, name='from_list', N=None):
11941201
if N is None:
11951202
self.colors = colors
@@ -1259,7 +1266,7 @@ def reversed(self, name=None):
12591266
name = self.name + "_r"
12601267

12611268
colors_r = list(reversed(self.colors))
1262-
new_cmap = ListedColormap(colors_r, name=name, N=self.N)
1269+
new_cmap = ListedColormap(colors_r, name=name)
12631270
# Reverse the over/under values too
12641271
new_cmap._rgba_over = self._rgba_under
12651272
new_cmap._rgba_under = self._rgba_over
@@ -1943,14 +1950,14 @@ def __getitem__(self, item):
19431950
if origin_1_as_int > self.M-1:
19441951
origin_1_as_int = self.M-1
19451952
one_d_lut = self._lut[:, origin_1_as_int]
1946-
new_cmap = ListedColormap(one_d_lut, name=f'{self.name}_0', N=self.N)
1953+
new_cmap = ListedColormap(one_d_lut, name=f'{self.name}_0')
19471954

19481955
elif item == 1:
19491956
origin_0_as_int = int(self._origin[0]*self.N)
19501957
if origin_0_as_int > self.N-1:
19511958
origin_0_as_int = self.N-1
19521959
one_d_lut = self._lut[origin_0_as_int, :]
1953-
new_cmap = ListedColormap(one_d_lut, name=f'{self.name}_1', N=self.M)
1960+
new_cmap = ListedColormap(one_d_lut, name=f'{self.name}_1')
19541961
else:
19551962
raise KeyError(f"only 0 or 1 are"
19561963
f" valid keys for BivarColormap, not {item!r}")

‎lib/matplotlib/contour.py

Copy file name to clipboardExpand all lines: lib/matplotlib/contour.py
+10-5Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,10 +183,14 @@ def clabel(self, levels=None, *,
183183
self.labelMappable = self
184184
self.labelCValueList = np.take(self.cvalues, self.labelIndiceList)
185185
else:
186-
cmap = mcolors.ListedColormap(colors, N=len(self.labelLevelList))
187-
self.labelCValueList = list(range(len(self.labelLevelList)))
188-
self.labelMappable = cm.ScalarMappable(cmap=cmap,
189-
norm=mcolors.NoNorm())
186+
# handling of explicit colors for labels:
187+
# make labelCValueList contain integers [0, 1, 2, ...] and a cmap
188+
# so that cmap(i) == colors[i]
189+
num_levels = len(self.labelLevelList)
190+
colors = cbook._resize_sequence(mcolors.to_rgba_array(colors), num_levels)
191+
self.labelMappable = cm.ScalarMappable(
192+
cmap=mcolors.ListedColormap(colors), norm=mcolors.NoNorm())
193+
self.labelCValueList = list(range(num_levels))
190194

191195
self.labelXYs = []
192196

@@ -738,7 +742,8 @@ def __init__(self, ax, *args,
738742
if self._extend_min:
739743
i0 = 1
740744

741-
cmap = mcolors.ListedColormap(color_sequence[i0:None], N=ncolors)
745+
cmap = mcolors.ListedColormap(
746+
cbook._resize_sequence(color_sequence[i0:], ncolors))
742747

743748
if use_set_under_over:
744749
if self._extend_min:

‎lib/matplotlib/tests/test_cbook.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_cbook.py
+17Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,23 @@ def test_sanitize_sequence():
463463
assert k == cbook.sanitize_sequence(k)
464464

465465

466+
def test_resize_sequence():
467+
a_list = [1, 2, 3]
468+
arr = np.array([1, 2, 3])
469+
470+
# already same length: passthrough
471+
assert cbook._resize_sequence(a_list, 3) is a_list
472+
assert cbook._resize_sequence(arr, 3) is arr
473+
474+
# shortening
475+
assert cbook._resize_sequence(a_list, 2) == [1, 2]
476+
assert_array_equal(cbook._resize_sequence(arr, 2), [1, 2])
477+
478+
# extending
479+
assert cbook._resize_sequence(a_list, 5) == [1, 2, 3, 1, 2]
480+
assert_array_equal(cbook._resize_sequence(arr, 5), [1, 2, 3, 1, 2])
481+
482+
466483
fail_mapping: tuple[tuple[dict, dict], ...] = (
467484
({'a': 1, 'b': 2}, {'alias_mapping': {'a': ['b']}}),
468485
({'a': 1, 'b': 2}, {'alias_mapping': {'a': ['a', 'b']}}),

‎lib/matplotlib/tests/test_colors.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_colors.py
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,8 +1165,8 @@ def test_pandas_iterable(pd):
11651165
# a single color
11661166
lst = ['red', 'blue', 'green']
11671167
s = pd.Series(lst)
1168-
cm1 = mcolors.ListedColormap(lst, N=5)
1169-
cm2 = mcolors.ListedColormap(s, N=5)
1168+
cm1 = mcolors.ListedColormap(lst)
1169+
cm2 = mcolors.ListedColormap(s)
11701170
assert_array_equal(cm1.colors, cm2.colors)
11711171

11721172

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.