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 eb02204

Browse filesBrowse files
committed
FIX: Error-handling for from_list inputs
Assume that the 'colors' argument is always a list of colors. If 'to_rgba_array' fails, attempt to unpack the values as a list of '(color, value)' tuples. Fixes #29042. Passing '(color, alpha)' tuples are nor correctly parsed as a list of colors. Check for range and monotony of values when unpacking (value, color) pairs. Implemented tests for different combinations of inputs.
1 parent b358c98 commit eb02204
Copy full SHA for eb02204

File tree

Expand file treeCollapse file tree

2 files changed

+52
-8
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+52
-8
lines changed

‎lib/matplotlib/colors.py

Copy file name to clipboardExpand all lines: lib/matplotlib/colors.py
+21-8Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"""
4141

4242
import base64
43-
from collections.abc import Sized, Sequence, Mapping
43+
from collections.abc import Sequence, Mapping
4444
import functools
4545
import importlib
4646
import inspect
@@ -1091,22 +1091,35 @@ def from_list(name, colors, N=256, gamma=1.0):
10911091
range :math:`[0, 1]`; i.e. 0 maps to ``colors[0]`` and 1 maps to
10921092
``colors[-1]``.
10931093
If (value, color) pairs are given, the mapping is from *value*
1094-
to *color*. This can be used to divide the range unevenly.
1094+
to *color*. This can be used to divide the range unevenly. The
1095+
values must increase monotonically from 0 to 1.
10951096
N : int
10961097
The number of RGB quantization levels.
10971098
gamma : float
10981099
"""
10991100
if not np.iterable(colors):
11001101
raise ValueError('colors must be iterable')
11011102

1102-
if (isinstance(colors[0], Sized) and len(colors[0]) == 2
1103-
and not isinstance(colors[0], str)):
1104-
# List of value, color pairs
1105-
vals, colors = zip(*colors)
1106-
else:
1103+
try:
1104+
# Assume the passed colors are a list of colors
1105+
# and not a (value, color) tuple.
1106+
r, g, b, a = to_rgba_array(colors).T
11071107
vals = np.linspace(0, 1, len(colors))
1108+
except Exception as e:
1109+
# Assume the passed values are a list of
1110+
# (value, color) tuples.
1111+
try:
1112+
_vals, _colors = itertools.zip_longest(*colors)
1113+
except Exception as e2:
1114+
raise e2 from e
1115+
vals = np.asarray(_vals)
1116+
if np.min(vals) < 0 or np.max(vals) > 1 or np.any(np.diff(vals) <= 0):
1117+
raise ValueError(
1118+
"the values passed in the (value, color) pairs "
1119+
"must increase monotonically from 0 to 1."
1120+
)
1121+
r, g, b, a = to_rgba_array(_colors).T
11081122

1109-
r, g, b, a = to_rgba_array(colors).T
11101123
cdict = {
11111124
"red": np.column_stack([vals, r, r]),
11121125
"green": np.column_stack([vals, g, g]),

‎lib/matplotlib/tests/test_colors.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_colors.py
+31Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,3 +1734,34 @@ def test_colorizer_vmin_vmax():
17341734
assert ca.vmax == 3.0
17351735
assert ca.norm.vmin == 1.0
17361736
assert ca.norm.vmax == 3.0
1737+
1738+
1739+
def test_LinearSegmentedColormap_from_list_color_alpha_tuple(colors):
1740+
"""
1741+
GitHub issue #29042: A bug in 'from_list' causes an error
1742+
when passing a tuple (str, float) where the string is a
1743+
color name or grayscale value and float is an alpha value.
1744+
"""
1745+
colors = [("red", 0.3), ("0.42", 0.1), "green"]
1746+
cmap = mcolors.LinearSegmentedColormap.from_list("lsc", colors, N=3)
1747+
assert_array_almost_equal(cmap([.0, 0.5, 1.]), to_rgba_array(colors))
1748+
1749+
1750+
@pytest.mark.parametrize("colors",
1751+
[[(0.42, "blue"), (.1, .1, .1, .1)],
1752+
["blue", (0.42, "red")],
1753+
["blue", (.1, .1, .1, .1), ("red", 2)],
1754+
[(0, "red"), (1.1, "blue")],
1755+
[(0.52, "red"), (0.42, "blue")]])
1756+
def test_LinearSegmentedColormap_from_list_invalid_inputs(colors):
1757+
with pytest.raises(ValueError):
1758+
mcolors.LinearSegmentedColormap.from_list("lsc", colors)
1759+
1760+
1761+
def test_LinearSegmentedColormap_from_list_value_color_tuple():
1762+
value_color_tuples = [(0, "red"), (0.6, "blue"), (1, "green")]
1763+
cmap = mcolors.LinearSegmentedColormap.from_list("lsc", value_color_tuples, N=11)
1764+
assert_array_almost_equal(
1765+
cmap([value for value, _ in value_color_tuples]),
1766+
to_rgba_array([color for _, color in value_color_tuples]),
1767+
)

0 commit comments

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