Python 获取 matplotlib 颜色循环状态
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13831549/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get matplotlib color cycle state
提问by mwaskom
Is it possible to query the current state of the matplotlib color cycle? In other words is there a function get_cycle_statethat will behave in the following way?
是否可以查询 matplotlib 颜色循环的当前状态?换句话说,是否有一个函数get_cycle_state会按以下方式运行?
>>> plot(x1, y1)
>>> plot(x2, y2)
>>> state = get_cycle_state()
>>> print state
2
Where I expect the state to be the index of the next color that will be used in a plot. Alternatively, if it returned the next color ("r" for the default cycle in the example above), that would be fine too.
我希望状态是将在绘图中使用的下一种颜色的索引。或者,如果它返回下一个颜色(上例中的默认循环为“r”),那也没关系。
采纳答案by Joe Kington
Accessing the color cycle iterator
访问颜色循环迭代器
There's no "user-facing" (a.k.a. "public") method to access the underlying iterator, but you can access it through "private" (by convention) methods. However, you'd can't get the state of an iteratorwithout changing it.
没有“面向用户”(又名“公共”)方法来访问底层迭代器,但您可以通过“私有”(按照约定)方法访问它。但是,如果iterator不更改它,您将无法获得它的状态。
Setting the color cycle
设置颜色周期
Quick aside: You can set the color/property cycle in a variety of ways (e.g. ax.set_color_cyclein versions <1.5 or ax.set_prop_cyclerin >=1.5). Have a look at the example here for version 1.5 or greater, or the previous style here.
顺便说一句:您可以通过多种方式设置颜色/属性周期(例如,ax.set_color_cycle在版本 <1.5 或ax.set_prop_cycler>=1.5 中)。在这里查看 1.5 版或更高版本的示例,或者这里以前的样式。
Accessing the underlying iterator
访问底层迭代器
However, while there's no public-facing method to access the iterable, you can access it for a given axes object (ax) through the _get_lineshelper class instance. ax._get_linesis a touch confusingly named, but it's the behind-the-scenes machinery that allows the plotcommand to process all of the odd and varied ways that plotcan be called. Among other things, it's what keeps track of what colors to automatically assign. Similarly, there's ax._get_patches_for_fillto control cycling through default fill colors and patch properties.
然而,虽然没有面向公众的方法来访问可迭代对象,但您可以ax通过_get_lines辅助类实例为给定的轴对象 ( )访问它。 ax._get_lines是一个令人困惑的名字,但它是幕后机制,允许plot命令处理所有plot可以调用的奇怪和不同的方式。除其他外,它是跟踪自动分配的颜色。同样,ax._get_patches_for_fill通过默认填充颜色和补丁属性来控制循环。
At any rate, the color cycle iterable is ax._get_lines.color_cyclefor lines and ax._get_patches_for_fill.color_cyclefor patches. On matplotlib >=1.5, this has changed to use the cyclerlibrary, and the iterable is called prop_cyclerinstead of color_cycleand yields a dictof properties instead of only a color.
无论如何,可迭代的颜色循环ax._get_lines.color_cycle适用于线条和ax._get_patches_for_fill.color_cycle补丁。在 matplotlib >=1.5 上,这已更改为使用cyclerlibrary,并且 iterable 被调用prop_cycler而不是color_cycle并产生一系列dict属性,而不仅仅是颜色。
All in all, you'd do something like:
总而言之,你会做这样的事情:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
color_cycle = ax._get_lines.color_cycle
# or ax._get_lines.prop_cycler on version >= 1.5
# Note that prop_cycler cycles over dicts, so you'll want next(cycle)['color']
You can't view the state of an iterator
您无法查看状态 iterator
However, this object is a "bare" iterator. We can easily get the next item (e.g. next_color = next(color_cycle), but that means that the next color after thatis what will be plotted. By design, there's no way to get the current state of an iterator without changing it.
然而,这个对象是一个“裸”的iterator。我们可以很容易地得到下一个项目(例如next_color = next(color_cycle),但是这意味着,在未来的颜色之后是什么将被绘制。在设计上,有没有办法得到一个迭代器的当前状态,而不改变它。
In v1.5or greater, it would be nice to get the cyclerobject that's used, as we could infer its current state. However, the cyclerobject itself isn't accessible (publicly or privately) anywhere. Instead, only the itertools.cycleinstance created from the cyclerobject is accessible. Either way, there's no way to get to the underlying state of the color/property cycler.
在v1.5或更大的范围内,获得使用的cycler对象会很好,因为我们可以推断其当前状态。但是,cycler对象本身无法在任何地方(公开或私密)访问。相反,只有itertools.cycle从cycler对象创建的实例是可访问的。无论哪种方式,都无法获得颜色/属性循环器的底层状态。
Match the color of the previously plotted item instead
改为匹配先前绘制的项目的颜色
In your case, it sounds like you're wanting to match the color of something that was just plotted. Instead of trying to determine what the color/property will be, set the color/etc of your new item based on the properties of what's plotted.
在你的情况下,听起来你想要匹配刚刚绘制的东西的颜色。不要试图确定颜色/属性是什么,而是根据绘制的属性设置新项目的颜色/等。
For example, in the case you described, I'd do something like this:
例如,在你描述的情况下,我会做这样的事情:
import matplotlib.pyplot as plt
import numpy as np
def custom_plot(x, y, **kwargs):
ax = kwargs.pop('ax', plt.gca())
base_line, = ax.plot(x, y, **kwargs)
ax.fill_between(x, 0.9*y, 1.1*y, facecolor=base_line.get_color(), alpha=0.5)
x = np.linspace(0, 1, 10)
custom_plot(x, x)
custom_plot(x, 2*x)
custom_plot(x, -x, color='yellow', lw=3)
plt.show()


It's not the only way, but its cleaner than trying to get the color of the plotted line before-hand, in this case.
在这种情况下,这不是唯一的方法,但它比事先尝试获取绘制线的颜色要干净。
回答by arynaq
Sure, this will do it.
当然,这会做到。
#rainbow
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0,2*np.pi)
ax= plt.subplot(1,1,1)
ax.plot(np.sin(x))
ax.plot(np.cos(x))
rainbow = ax._get_lines.color_cycle
print rainbow
for i, color in enumerate(rainbow):
if i<10:
print color,
Gives:
给出:
<itertools.cycle object at 0x034CB288>
r c m y k b g r c m
Here is the itertools function that matplotlib uses itertools.cycle
这里是 matplotlib 使用itertools.cycle的 itertools 函数
Edit: Thanks for the comment, it seems that it is not possible to copy an iterator. An idea would be to dump a full cycle and keep track of which value you are using, let me get back on that.
编辑:感谢您的评论,似乎无法复制迭代器。一个想法是转储一个完整的周期并跟踪您正在使用的值,让我回到那个。
Edit2: Allright, this will give you the next color and make a new iterator that behaves as if next was not called. This does not preserve the order of coloring, just the next color value, I leave that to you.
Edit2:好的,这会给你下一个颜色并创建一个新的迭代器,它的行为就像没有调用 next 一样。这不保留着色的顺序,只保留下一个颜色值,我把它留给你。
This gives the following output, notice that steepness in the plot corresponds to index, eg first g is the bottomest graph and so on.
这给出了以下输出,注意图中的陡度对应于索引,例如第一个 g 是最底部的图形等等。
#rainbow
import matplotlib.pyplot as plt
import numpy as np
import collections
import itertools
x = np.linspace(0,2*np.pi)
ax= plt.subplot(1,1,1)
def create_rainbow():
rainbow = [ax._get_lines.color_cycle.next()]
while True:
nextval = ax._get_lines.color_cycle.next()
if nextval not in rainbow:
rainbow.append(nextval)
else:
return rainbow
def next_color(axis_handle=ax):
rainbow = create_rainbow()
double_rainbow = collections.deque(rainbow)
nextval = ax._get_lines.color_cycle.next()
double_rainbow.rotate(-1)
return nextval, itertools.cycle(double_rainbow)
for i in range(1,10):
nextval, ax._get_lines.color_cycle = next_color(ax)
print "Next color is: ", nextval
ax.plot(i*(x))
plt.savefig("SO_rotate_color.png")
plt.show()
Console
安慰
Next color is: g
Next color is: c
Next color is: y
Next color is: b
Next color is: r
Next color is: m
Next color is: k
Next color is: g
Next color is: c


回答by Andi
Note: In the latest versions of matplotlib (>= 1.5) _get_lineshas changed. You now need to use next(ax._get_lines.prop_cycler)['color']in Python 2 or 3 (or ax._get_lines.prop_cycler.next()['color']in Python 2) to get the next color from the color cycle.
注意:在最新版本的 matplotlib (>= 1.5)_get_lines中发生了变化。现在,您需要使用next(ax._get_lines.prop_cycler)['color']在Python 2或3(或ax._get_lines.prop_cycler.next()['color']在Python中2),以获得从颜色周期的下一个颜色。
Wherever possible use the more direct approach shown in the lower part of @joe-kington's answer. As _get_linesis not API-facing it might change again in a not backward compatible manner in the future.
尽可能使用@joe-kington 答案下半部分中显示的更直接的方法。由于_get_lines不是面向 API 的,它将来可能会以不向后兼容的方式再次更改。
回答by Carson
I just want to add onto what @Andi said above. Since color_cycleis deprecated in matplotlib 1.5, you have to use prop_cycler, however, Andi's solution (ax._get_lines.prop_cycler.next()['color']) returned this error for me:
我只想补充上面@Andi 所说的内容。由于color_cycle在 matplotlib 1.5 中已弃用,因此您必须使用prop_cycler,但是,Andi 的解决方案 ( ax._get_lines.prop_cycler.next()['color']) 为我返回了此错误:
AttributeError: 'itertools.cycle' object has no attribute 'next'
AttributeError: 'itertools.cycle' 对象没有属性 'next'
The code that worked for me was: next(ax._get_lines.prop_cycler), which actually isn't far off from @joe-kington's original response.
对我next(ax._get_lines.prop_cycler)有用的代码是:,实际上与@joe-kington 的原始回复相差不远。
Personally, I ran into this problem when making a twinx() axis, which reset the color cycler. I needed a way to make the colors cycle correctly because I was using style.use('ggplot'). There might be an easier/better way to do this, so feel free to correct me.
就个人而言,我在制作 twinx() 轴时遇到了这个问题,这会重置颜色循环器。我需要一种方法来使颜色正确循环,因为我使用的是style.use('ggplot'). 可能有更简单/更好的方法来做到这一点,所以请随时纠正我。
回答by Mike DePalatis
Here's a way that works in 1.5 which will hopefully be future-proof as it doesn't rely on methods prepended with underscores:
这是一种在 1.5 中有效的方法,它有望面向未来,因为它不依赖于带有下划线的方法:
colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]
This will give you a list of the colors defined in order for the present style.
这将为您提供按当前样式定义的颜色列表。
回答by freidrichen
Since matplotlib uses itertools.cyclewe can actually look through the entire color cycle and then restore the iterator to its previous state:
由于使用 matplotlib,itertools.cycle我们实际上可以查看整个颜色循环,然后将迭代器恢复到以前的状态:
def list_from_cycle(cycle):
first = next(cycle)
result = [first]
for current in cycle:
if current == first:
break
result.append(current)
# Reset iterator state:
for current in cycle:
if current == result[-1]:
break
return result
This should return the list without changing the state of the iterator.
这应该返回列表而不更改迭代器的状态。
Use it with matplotlib >= 1.5:
将它与 matplotlib >= 1.5 一起使用:
>>> list_from_cycle(ax._get_lines.prop_cycler)
[{'color': 'r'}, {'color': 'g'}, {'color': 'b'}]
or with matplotlib < 1.5:
或 matplotlib < 1.5:
>>> list_from_cycle(ax._get_lines.color_cycle)
['r', 'g', 'b']
回答by jkokorian
In matplotlib version 2.2.3 there is a get_next_color()method on the _get_linesproperty:
在 matplotlib 版本 2.2.3 中有一个get_next_color()关于_get_lines属性的方法:
import from matplotlib import pyplot as plt
fig, ax = plt.subplots()
next_color = ax._get_lines.get_next_color()
get_next_color()returns an html color string, and advances the color cycle iterator.
get_next_color()返回一个 html 颜色字符串,并推进颜色循环迭代器。
回答by sancho.s ReinstateMonicaCellio
How to access the color (and complete style) cycle?
如何访问颜色(和完整的样式)循环?
The current state is stored in ax._get_lines.prop_cycler.
There are no built-in methods to expose the "base list" for a generic itertools.cycle, and in particular for ax._get_lines.prop_cycler(see below).
当前状态存储在ax._get_lines.prop_cycler. 没有内置方法来公开泛型的“基本列表” itertools.cycle,特别是ax._get_lines.prop_cycler(见下文)。
I have posted herea few functions to get info on a itertools.cycle.
One could then use
我在这里发布了一些函数来获取有关itertools.cycle. 然后可以使用
style_cycle = ax._get_lines.prop_cycler
curr_style = get_cycle_state(style_cycle) # <-- my (non-builtin) function
curr_color = curr_style['color']
to get the current color without changing the state of the cycle.
在不改变循环状态的情况下获取当前颜色。
TL;DR
TL; 博士
Where is the color (and complete style) cycle stored?
颜色(和完整样式)循环存储在哪里?
The style cycle is stored in two different places, one for the default, and one for the currentaxes (assuming import matplotlib.pyplot as pltand axis an axis handler):
样式循环存储在两个不同的位置,一个用于default,另一个用于当前轴(假设import matplotlib.pyplot as plt和ax是轴处理程序):
default_prop_cycler = plt.rcParams['axes.prop_cycle']
current_prop_cycle = ax._get_lines.prop_cycler
Note these have different classes. The default is a "base cycle setting" and it does not know about any current state for any axes, while the current knows about the cycle to follow and its current state:
注意这些有不同的类。默认值是“基本循环设置”,它不知道任何轴的任何当前状态,而当前知道要遵循的循环及其当前状态:
print('type(default_prop_cycler) =', type(default_prop_cycler))
print('type(current_prop_cycle) =', type(current_prop_cycle))
[]: type(default_prop_cycler) = <class 'cycler.Cycler'>
[]: type(current_prop_cycle) = <class 'itertools.cycle'>
The default cycle may have several keys (properties) to cycle, and one can get only the colors:
默认循环可能有几个键(属性)可以循环,一个只能得到颜色:
print('default_prop_cycler.keys =', default_prop_cycler.keys)
default_prop_cycler2 = plt.rcParams['axes.prop_cycle'].by_key()
print(default_prop_cycler2)
print('colors =', default_prop_cycler2['color'])
[]: default_prop_cycler.keys = {'color', 'linestyle'}
[]: {'color': ['r', 'g', 'b', 'y'], 'linestyle': ['-', '--', ':', '-.']}
[]: colors = ['r', 'g', 'b', 'y']
One could even change the cyclerto use for a given axes, after defining that custom_prop_cycler, with
人们甚至可以改变cycler使用对于给定的axes,定义,经过custom_prop_cycler与
ax.set_prop_cycle(custom_prop_cycler)
But there are no built-in methods to expose the "base list" for a generic itertools.cycle, and in particular for ax._get_lines.prop_cycler.
但是没有内置方法可以公开泛型的“基本列表” itertools.cycle,尤其是ax._get_lines.prop_cycler.
回答by Akim AKBA5439
The simplest way possible I could find without doing the whole loop through the cycler is ax1.lines[-1].get_color().
在不通过循环仪进行整个循环的情况下,我能找到的最简单的方法是ax1.lines[-1].get_color().

