是否可以查询matplotlib颜色循环的当前状态?换句话说,是否有一个函数get_cycle_state
将按以下方式运行?
>>> plot(x1, y1)
>>> plot(x2, y2)
>>> state = get_cycle_state()
>>> print state
2
我希望状态是将在绘图中使用的下一种颜色的索引。或者,如果它返回下一个颜色(上例中默认循环的“r”),那也没关系。
答案 0 :(得分:96)
没有“面向用户”(a.k.a。“public”)方法来访问底层迭代器,但您可以通过“私有”(按惯例)方法访问它。但是,如果不更改它,您将无法获得iterator
的状态。
快速放弃:您可以通过多种方式设置颜色/属性周期(例如版本中的ax.set_color_cycle
< 1.5或>中的ax.set_prop_cycler
= 1.5)。请查看example here for version 1.5 or greater或previous style here。
但是,虽然没有面向公众的方法来访问iterable,但您可以通过ax
帮助器类实例访问给定轴对象(_get_lines
)。 ax._get_lines
是一个令人困惑的名字,但它是幕后机制,允许plot
命令处理plot
可以调用的所有奇怪和多变的方式。除此之外,它还可以跟踪自动分配的颜色。同样,有ax._get_patches_for_fill
来控制通过默认填充颜色和补丁属性的循环。
无论如何,颜色循环可迭代线为ax._get_lines.color_cycle
,补丁为ax._get_patches_for_fill.color_cycle
。在matplotlib> = 1.5时,它已更改为use the cycler
library,并且可迭代名为prop_cycler
而不是color_cycle
,并且产生dict
个属性而不是仅有颜色。
总而言之,你会做类似的事情:
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']
iterator
但是,此对象是“裸”iterator
。我们可以轻松获得下一个项目(例如next_color = next(color_cycle)
,但这意味着之后的下一个颜色将被绘制。通过设计,无法获得当前的状态迭代器没有改变它。
在v1.5
或更高版本中,获取使用的cycler
对象会很好,因为我们可以推断出它的当前状态。但是,cycler
对象本身无法在任何地方(公开或私下)访问。相反,只能访问从itertools.cycle
对象创建的cycler
实例。无论哪种方式,都无法进入颜色/属性循环器的基础状态。
在你的情况下,听起来你想要匹配刚绘制的东西的颜色。不要试图确定颜色/属性是什么,而是根据绘制内容的属性设置新项目的颜色/等。
例如,在你描述的情况下,我会做这样的事情:
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()
这不是唯一的方法,但在这种情况下,它比在前手绘制线条的颜色更干净。
答案 1 :(得分:14)
注意:在最新版本的matplotlib(> = 1.5)_get_lines
已更改。您现在需要在Python 2或3(或Python 2中的next(ax._get_lines.prop_cycler)['color']
)中使用ax._get_lines.prop_cycler.next()['color']
来获取颜色循环中的下一个颜色。
尽可能使用@ joe-kington的答案下半部分中显示的更直接的方法。由于_get_lines
不面向API,因此未来可能会以不向后兼容的方式再次发生变化。
答案 2 :(得分:13)
这是一种在1.5中工作的方式,希望能够面向未来,因为它不依赖于下划线前面的方法:
colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]
这将为您提供为当前样式定义的颜色列表。
答案 3 :(得分:6)
当然,这样做会。
#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,
给出:
<itertools.cycle object at 0x034CB288>
r c m y k b g r c m
这是matplotlib使用itertools.cycle
的itertools函数编辑:感谢您的评论,似乎无法复制迭代器。一个想法是转储一个完整的周期并跟踪你正在使用的值,让我重新开始。
Edit2:好的,这将为您提供下一个颜色并创建一个新的迭代器,其行为就像下一个未被调用一样。这不会保留着色顺序,只保留下一个颜色值,我留给你。
这给出了以下输出,注意图中的陡度对应于索引,例如,第一个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()
控制台
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
答案 4 :(得分:4)
我只想补充@Andi上面所说的内容。由于matplotlib 1.5中不推荐使用color_cycle
,因此您必须使用prop_cycler
,但Andi的解决方案(ax._get_lines.prop_cycler.next()['color']
)会为我返回此错误:
AttributeError:&#39; itertools.cycle&#39;对象没有属性&#39; next&#39;
对我有用的代码是:next(ax._get_lines.prop_cycler)
,它实际上与@ joe-kington的原始回复相去甚远。
就个人而言,我在制作一个双x()轴时会遇到这个问题,这会重置色彩循环器。我需要一种方法来使颜色正确循环,因为我使用的是style.use('ggplot')
。可能有一种更容易/更好的方法来做到这一点,所以请随意纠正我。
答案 5 :(得分:1)
由于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
这应该返回列表而不改变迭代器的状态。
将它与matplotlib&gt; = 1.5:
一起使用>>> list_from_cycle(ax._get_lines.prop_cycler)
[{'color': 'r'}, {'color': 'g'}, {'color': 'b'}]
或使用matplotlib&lt; 1.5:
>>> list_from_cycle(ax._get_lines.color_cycle)
['r', 'g', 'b']
答案 6 :(得分:0)
在没有执行整个循环的情况下,我可能找到的最简单的方法是ax1.lines[-1].get_color()
。
答案 7 :(得分:-1)
在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()
返回html颜色字符串,并推进颜色循环迭代器。
答案 8 :(得分:-1)
如何访问颜色(和完整样式)循环?
当前状态存储在ax._get_lines.prop_cycler
中。
没有内置的方法可以显示通用itertools.cycle
,尤其是ax._get_lines.prop_cycler
的“基本列表”(请参见下文)。
我已经发布了here的一些函数来获取有关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']
获取当前颜色,而无需更改循环状态。
TL; DR
颜色(和完整样式)周期存储在哪里?
样式周期存储在两个不同的位置,一个存放 default ,另一个存放在 current 轴(假设import matplotlib.pyplot as plt
和{{1} }是轴处理程序):
ax
请注意,它们具有不同的类。 默认值为“基本循环设置”,它不知道任何轴的任何当前状态,而当前则知道要跟随的循环及其当前状态:
default_prop_cycler = plt.rcParams['axes.prop_cycle']
current_prop_cycle = ax._get_lines.prop_cycler
默认循环可能具有多个要循环的键(属性),并且一个键只能获得颜色:
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'>
使用{p>定义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']
之后,甚至可以更改cycler
用于给定的axes
custom_prop_cycler
但是,没有内置方法来公开通用ax.set_prop_cycle(custom_prop_cycler)
,尤其是itertools.cycle
的“基本列表”。
答案 9 :(得分:-1)
我已经为此苦苦挣扎了好几次。 这是 Andis answer 的最小工作示例。
import numpy as np
import matplotlib.pyplot as plt
xs = np.arange(10)
fig, ax = plt.subplots()
for ii in range(3):
color = next(ax._get_lines.prop_cycler)['color']
lbl = 'line {:d}, color {:}'.format(ii, color)
ys = np.random.rand(len(xs))
ax.plot(xs, ys, color=color, label=lbl)
ax.legend()