Why is matplotlib coloring my plot with so many colors?

落花浮王杯 提交于 2021-02-19 04:30:08

问题


I am plotting multiple objects, both consisting of multiple straight lines. To do so, I use a list of colors and assign one to each object. The desired result looks like this:
I am doing this with the command plt.plot, providing a start and end point, and a color.

While trying to get to this result, I made a mistake, and instead of names like 'pink', I provided values like (0, 0.75, 0).
Which resulted in this:

Why does matplotlib behave this way? I would like to understand how it comes that each segment has its own color, seemingly chosen at random, when I have always provided the same incorrect input.

I was unable to find documentation of the behaviour when no correct input value is passed. If there is documentation, a quote of the relevant part would already constitute an answer if matplotlib actually just chooses at random every time.

The same behaviour happens when I pass False instead of a color.


MCVE:

import matplotlib.pyplot as plt

# Line in black
plt.plot([-1,-1], [-1,1], 'k')
# Line in bad color
plt.plot([0,0],[-1,1], False)
# Line in same bad color
plt.plot([1,1],[-1,1], False)
# Line in other bad color
plt.plot([2,2],[-1,1], (0,0.75,0))
# Line in same other bad color
plt.plot([3,3],[-1,1], (0,0.75,0))
plt.show()


Note:
I am not looking for how to get my desired result by passing a constant color. I managed that. But on the way there, I encountered this behaviour, which I'd like to understand.
Based on the comments, it seems likely that there is some documented and well-known functionality in pyplot that simply uses a color cycle and takes the next color in it whenever no valid color is provided. I am not able to find documentation on that though, so I would like either some documentation quote, or the answer that this is undocumented behaviour, or something along those lines.

It is also worth pointing out that something in the middle of the image was also drawn when I was using invalid color parameters, but not when using correct values. Why?


回答1:


The call signature of plot is completely crazy. This is because it has grown over time and is one of the most used functions, hence it's always kept backward compatible.

The documentation states the following ways to call this function.

plot([x], y, [fmt], data=None, **kwargs)
plot([x], y, [fmt], [x2], y2, [fmt2], ..., **kwargs)

Arguments in square brackets are optional and the ellipses denote an arbitrary number of further arguments to be passed.

Going through the cases from above, and renaming the respective arguments:

1.

plt.plot([-1,-1], [-1,1], 'k')
plt.plot(   x   ,    y  , fmt)

As expected 'k' is the format to be used.

2.

plt.plot([0,0],[-1,1], False)
plt.plot(  x  ,   y  ,   y2 )

Here, False is no valid format string. Hence it is interpreted as data for a new line. Since there is no other following argument that can be interpreted, it cannot be x2, hence it must be y2. False is equivalent to 0. So you would get a single point at (0,0), which you don't see in the plot, because there is no marker specified. If you were to use

plt.plot([0,0],[-1,1], False, "o")

instead, you'd see the single point in orange.

3.

Same as above. The only difference is that you get the line in a different color according to the color cycler in use (see below in this answer).

4.

plt.plot([2,2],[-1,1], (0,0.75,0))
plt.plot(  x  ,   y  ,     y2    )

Again, the third argument is no valid format string. It is again interpreted as the y values of a further line. This time, in contrast to 2. and 3., y2 contains several coordinates. Therefore a line along the points (0,0), (1,0.75), (2,0) is drawn.


In all but the first case, no color is specified. In that case according to the docs

By default, each line is assigned a different style specified by a 'style cycle'. The fmt and line property parameters are only necessary if you want explicit deviations from these defaults. Alternatively, you can also change the style cycle using the 'axes.prop_cycle' rcParam.

Since the default property cycler only contains color, you will hence get the same linestyle everywhere, but in a different color.

You may print the default cycler

print(plt.rcParams["axes.prop_cycle"])

# cycler('color', ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b',
#                   '#e377c2', '#7f7f7f', '#bcbd22', '#17becf'])

Or you may set it

plt.rcParams["axes.prop_cycle"] = plt.cycler("color", ["red", "#001eff", (0, 0.75, 0)])

An example is available on the matplotlib page: Styling with cycler and also Colors in the default property cycle

cycler also has its own documentation page, https://matplotlib.org/cycler/ as it may equally be used for other things outside of matplotlib.

Coming back to the start of the question; in order to get all lines in the same color, it is possible to set the color cycler to a single color

plt.rcParams["axes.prop_cycle"] = plt.cycler("color", ["k"])

In this case, all lines in the axes will appear black.




回答2:


Without seeing the code it is hard to answer, But can you try assign colour explicitly? What is more, you can not do plt.plot(x,y,color), you need to write the name of params explicitly like this plt.plot(x,y,c = color) or plt.plot(x,y,color = color)

You can try this code:

import matplotlib.pyplot as plt


blue = (0,0,0.75)
green = (0, 0.75, 0)
# Line in black
plt.plot([-1,-1], [-1,1], color = blue)
# Line in bad color
plt.plot([0,0],[-1,1] , color = blue)
# Line in same bad color
plt.plot([1,1],[-1,1], color = blue)
# Line in other bad color
plt.plot([2,2],[-1,1], color = green)
# Line in same other bad color
plt.plot([3,3],[-1,1], color = green)
plt.show()

And the reason of you can use plt.plot([3,3],[-1,1], "green") rather than plt.plot([3,3],[-1,1], green) is from the plot documentaion.

The default third parameter is fmt and its definition is, A format string consists of a part for color, marker and line: fmt = '[color][marker][line]'. I think the plot function will work properly if it recognize the third parameter is the accepted string.

Instead of feeding '(0, 0.75, 0)' than "green", the function will treat '(0, 0.75, 0)' as a line segment of x = (0, 1, 2) y =(0, 0.75, 0), so that is why there is a additional line segment on your plot. And normally the plot will assign a default color to it.



来源:https://stackoverflow.com/questions/53122311/why-is-matplotlib-coloring-my-plot-with-so-many-colors

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!