Repository navigation
Description
Bug 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
Activity
ksunden commentedon Jun 21, 2024
This is a result of the
(color, alpha)version of specifying colors that was introduced in 3.8.0That 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 commentedon Jun 21, 2024
Just catching the
TypeErrorwithinis_color_likemakes the error consistent with the list casercomer commentedon Jun 21, 2024
Note there is no issue with functions that do take a color sequence
story645 commentedon Jun 21, 2024
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 commentedon Jun 21, 2024
It does seem odd that by default you get 2 colors but you cannot specify 2 colors.
timhoffm commentedon Jun 22, 2024
The
_is_color_likechange 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).
jklymak commentedon 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.