获取matplotlib颜色循环状态
有没有可能查询matplotlib颜色循环的当前状态? 换句话说,是否有一个函数get_cycle_state
将以下列方式performance?
>>> plot(x1, y1) >>> plot(x2, y2) >>> state = get_cycle_state() >>> print state 2
在那里,我期望的状态是下一个将用于阴谋的颜色的指标。 或者,如果它返回下一个颜色(上面例子中的默认循环“r”),那也可以。
访问颜色循环迭代器
没有“面向用户”(又名“public”)方法来访问底层迭代器,但是你可以通过“私有”(惯例)方法来访问它。 但是,如果不更改它,你将无法获得iterator
的状态。
设置颜色循环
快速放在一边:您可以通过多种方式设置颜色/属性周期(例如,版本<1.5的ax.set_prop_cycler
或> = 1.5的ax.set_prop_cycler
)。 看看1.5版本或更高版本的例子 ,或者这里的上一个样式 。
访问基础迭代器
但是,虽然没有公开的方法来访问迭代,但您可以通过_get_lines
helper类实例访问给定的轴对象( ax
)。 ax._get_lines
是一个容易混淆的名字,但它是幕后机制,允许plot
指挥处理所有可以调用plot
的奇怪而多样的方式。 除此之外,它跟踪什么颜色自动分配。 同样,有ax._get_patches_for_fill
来控制通过默认填充颜色和补丁属性的循环。
无论如何,迭代的颜色循环是ax._get_patches_for_fill.color_cycle
,补丁是ax._get_lines.color_cycle
。 在matplotlib> = 1.5上,这已经改变为使用cycler
库 ,迭代器被称为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)
,但这意味着之后的下一个颜色将被绘制出来。通过devise,没有办法获得迭代器的当前状态而不改变它。
在v1.5
或更高版本中,获取使用的cycler
对象将是很好的,因为我们可以推断它的当前状态。 然而, cycler
对象本身不能在任何地方(公共或私人)访问。 相反,只有从itertools.cycle
对象创build的itertools.cycle
实例是可访问的。 无论哪种方式,都无法达到颜色/属性循环仪的基本状态。
匹配先前绘制的项目的颜色
在你的情况下,这听起来像你想要匹配刚刚绘制的东西的颜色。 不要尝试确定颜色/属性是什么,根据绘制的属性设置新项目的颜色等。
例如,在你描述的情况下,我会做这样的事情:
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()
这并不是唯一的方法,但是在这种情况下,它要比事先弄清绘制线的颜色更清洁。
注意:在最新版本的matplotlib(> = 1.5)中_get_lines
已经改变。 您现在需要使用Python 2或Python 3中的next(ax._get_lines.prop_cycler)['color']
(或Python 2中的ax._get_lines.prop_cycler.next()['color']
)来获取下一个颜色颜色循环。
尽可能使用@ joe-kington答案下半部分显示的更直接的方法。 由于_get_lines
不是面向API的,它将来可能会以不兼容的方式再次改变。
当然,这将做到这一点。
#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> rcmykbgrcm
这里是matplotlib使用itertools.cycle的itertools函数
编辑:感谢评论,似乎是不可能复制一个迭代器。 一个想法是转储一个完整的周期,并跟踪你正在使用的价值,让我回到这一点。
编辑2:好吧,这将给你下一个颜色,并使一个新的迭代器,就好像next未被调用。 这不保留着色的顺序,只是下一个颜色值,我把它留给你。
这给出以下输出,注意图中的陡度对应于索引,例如,第一个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
这里有一个在1.5中工作的方式,这将有望成为未来的保证,因为它不依赖于下划线前面的方法:
colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]
这将给你一个为目前的风格定义的颜色列表。
我只是想补充@Andi上面所说的。 由于color_cycle
在matplotlib 1.5中被弃用,所以你必须使用prop_cycler
,然而,Andi的解决scheme( ax._get_lines.prop_cycler.next()['color']
)为我返回了这个错误:
AttributeError:'itertools.cycle'对象没有属性'next'
我的代码是: next(ax._get_lines.prop_cycler)
,这实际上离@ joe-kington的原始响应并不遥远。
就我个人而言,在制作twinx()轴时遇到了这个问题,它重置了色循环。 我需要一种方法来使颜色循环正确,因为我正在使用style.use('ggplot')
。 有可能是一个更容易/更好的方式来做到这一点,所以请随时纠正我。
由于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> = 1.5一起使用:
>>> list_from_cycle(ax._get_lines.prop_cycler) [{'color': 'r'}, {'color': 'g'}, {'color': 'b'}]
或用matplotlib <1.5:
>>> list_from_cycle(ax._get_lines.color_cycle) ['r', 'g', 'b']