GeezerVison is showing github.com — [Bug]: Setting exactly 2 colors with tuple in `plot` method gives confusing error · Issue #28434 · matplotlib/matplotlib
[Bug]: Setting exactly 2 colors with tuple in plot method gives confusing error #28434DescriptionBug summary
If one attempts to set the color parameter to a tuple of length 2, a nonsense error message is returned.
Code for reproduction
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.array([np.sin(x), np.cos(x)]).T
plt.plot(x, y, label=("sin(x)", "cos(x)")) # works
plt.plot(x, y, label=("sin(x)", "cos(x)"), color=("red", "blue")) # causes strange error
plt.legend()
plt.show()
Actual outcome
Traceback (most recent call last):
File "/Users/miles/Desktop/thing.py", line 8, in
plt.plot(x, y, label=("sin(x)", "cos(x)"), color=("red", "blue")) # causes error
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/matplotlib/pyplot.py", line 3708, in plot
return gca().plot(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/matplotlib/axes/_axes.py", line 1779, in plot
lines = [*self._get_lines(self, *args, data=data, **kwargs)]
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/matplotlib/axes/_base.py", line 296, in call
yield from self._plot_args(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/matplotlib/axes/_base.py", line 534, in _plot_args
return [l[0] for l in result]
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/matplotlib/axes/_base.py", line 534, in
return [l[0] for l in result]
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/matplotlib/axes/_base.py", line 527, in
result = (make_artist(axes, x[:, j % ncx], y[:, j % ncy], kw,
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/matplotlib/axes/_base.py", line 335, in _makeline
seg = mlines.Line2D(x, y, **kw)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/matplotlib/lines.py", line 376, in init
self.set_color(color)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/matplotlib/lines.py", line 1066, in set_color
mcolors._check_color_like(color=color)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/matplotlib/colors.py", line 245, in _check_color_like
if not is_color_like(v):
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/matplotlib/colors.py", line 227, in is_color_like
to_rgba(c)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/matplotlib/colors.py", line 309, in to_rgba
rgba = _to_rgba_no_colorcycle(c, alpha)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/matplotlib/colors.py", line 334, in _to_rgba_no_colorcycle
if alpha is not None and not 0 <= alpha <= 1:
TypeError: '<=' not supported between instances of 'int' and 'str'
Expected outcome
Either: (1) works as expected as passing a tuple to label does, or, if this won't be supported, (2) a more sensical error message is returned, like if ["red", "blue"] were passed.
Additional information
This difficult-to-interpret error seems to be caused by the if statement of line 328 in _to_rgba_no_colorcycle in colors.py, which says if isinstance(c, tuple) and len(c) == 2. If I comment out this if statement, then the error message gives the normal ValueError: ('red', 'blue') is not a valid value for color... message. Of course, it would be great if multiple colors were supported here, but I understand if there is a bigger reason why it is not supported.
Operating system
macOS 14.4.1
Matplotlib Version
3.9.0
Matplotlib Backend
macosx
Python version
3.9.6
Jupyter version
No response
Installation
pip Activityksunden commented on Jun 21, 2024 This is a result of the (color, alpha) version of specifying colors that was introduced in 3.8.0
That is why it is specifically tuples (not lists) and specifically length 2...
My gut reaction is that the new color specifier is useful enough and the workaround (casting to list) is easy enough that I'm inclined towards keeping current behavior...
On the other hand, it may be reasonable to narrow the condition further to "is the second entry in a length 2 tuple a number"... and if it is not, treat it as a standard sequence of 2 colors instead...
As long as numbers are not valid color specifiers, this would differentiate the cases. I believe that is the case (though string floating point values are valid color specifiers for shades of gray...). Because if a number were a valid color specifier, then this would be an ambiguous case. rcomer commented on Jun 21, 2024 Just catching the TypeError within is_color_like makes the error consistent with the list case
diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py
index c4e5987fdf..f6e78dc3e4 100644
--- a/lib/matplotlib/colors.py
+++ b/lib/matplotlib/colors.py
@@ -225,7 +225,7 @@ def is_color_like(c):
return True
try:
to_rgba(c)
- except ValueError:
+ except (ValueError, TypeError):
return False
else:
return True
ValueError: ('red', 'blue') is not a valid value for color: supported inputs are (r, g, b) and (r, g, b, a) 0-1 float tuples; '#rrggbb', '#rrggbbaa', '#rgb', '#rgba' strings; named color strings; string reprs of 0-1 floats for grayscale values; 'C0', 'C1', ... strings for colors of the color cycle; and pairs combining one of the above with an alpha value
rcomer commented on Jun 21, 2024 Note there is no issue with functions that do take a color sequence
plt.scatter([1, 2], [4, 5], c=("red", "blue"))

story645 commented on Jun 21, 2024
Note there is no issue with functions that do take a color sequence
Do we want to allow this function to take a color sequence? It would be in line w/ the other PRs that are vectorizing inputs. rcomer commented on Jun 21, 2024 It does seem odd that by default you get 2 colors but you cannot specify 2 colors. Reacted by hannah and miles timhoffm commented on Jun 22, 2024 The _is_color_like change proposed by @rcomer above should be applied no matter what.
I'm a bit hesitant on supporting sequences for color. If we do that, we'd have to expand to all parameters consistently. Note in particular that some parameters use sequences as single-value represenations already, e.g. colors and linestyles, so detection of sequence-of-parameters is non-trivial. It's not completely unreasonable to support seqnce-of-parameters, but adds significant complexity to an already very complex function. If somebody implements this, I'd like to see an as-clean-as possible implementation.
When adding label sequences, we've explicitly done that as an exception without the promise to support sequences on all parameters. The argument is that all other parameters can be addressed through the property cycle, i.e. can be configured up-front to a multiple-data plot. That's not possible for labels. See #16178 (comment). Reacted by Ruth Comer, miles and Jody Klymak jklymak commented on Jun 22, 2024 I think that in general the idea of two d conveniences for one d plotting functions is more trouble than it is worth and leads to an inconsistent API. In fact, I'd argue that allowing lists of labels was a bad idea to start with. If people need to style individual columns of a data set differently, and they don't want to deal with our cycler, they can use a trivial for-loop. (I see I am repeating myself from #16178)
Of course I do agree that the error message is terrible here.
MetadataMetadataDevelopmentNo branches or pull requestsIssue actions
|