是否可以查询matplotlib颜色循环的当前状态?换句话说,是否有一个函数get_cycle_state
可以像下面这样工作?
>>> plot(x1, y1)
>>> plot(x2, y2)
>>> state = get_cycle_state()
>>> print state
2
我希望状态可以成为绘制图形中下一个要使用的颜色的索引。或者,如果它返回下一个颜色(例如上面示例中的默认循环中的“r”),那也可以。
是否可以查询matplotlib颜色循环的当前状态?换句话说,是否有一个函数get_cycle_state
可以像下面这样工作?
>>> plot(x1, y1)
>>> plot(x2, y2)
>>> state = get_cycle_state()
>>> print state
2
我希望状态可以成为绘制图形中下一个要使用的颜色的索引。或者,如果它返回下一个颜色(例如上面示例中的默认循环中的“r”),那也可以。
没有“公共”方法可以访问底层迭代器,但可以通过“私有”(惯例上)方法访问它。但是,你无法在改变迭代器的情况下获取其状态。
快速说一下:你可以以多种方式设置颜色/属性循环(例如,在版本<1.5中使用ax.set_color_cycle
或在版本>=1.5中使用ax.set_prop_cycler
)。请查看此处示例(版本1.5或更高版本)或此处旧版样式。
然而,虽然没有公共方法可以访问可迭代对象,但你可以通过_get_lines
辅助类实例来为给定的轴对象(ax
)访问它。虽然ax._get_lines
的命名有点令人困惑,但它是幕后机制,可以处理所有plot
命令可能被调用的奇怪和多变的方式。它是跟踪自动分配颜色的关键之一。同样,ax._get_patches_for_fill
用于控制默认填充颜色和 path 属性的循环。
总之,颜色循环可迭代对象是ax._get_lines.color_cycle
(线条)和ax._get_patches_for_fill.color_cycle
(路径)。在 matplotlib >=1.5 中,这已更改为使用cycler库,可迭代对象称为prop_cycler
而不是color_cycle
,并且产生一个属性字典而不仅仅是颜色。
总之,你可以这样做:
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
。我们可以轻松地获取下一个项目(例如,next_color = next(color_cycle)
),但这意味着接下来的颜色之后将被绘制。按设计,没有办法在不改变迭代器的情况下获取其当前状态。
在v1.5
或更高版本中,获取使用的cycler
对象会比较好,因为我们可以推断出它的当前状态。但是,cycler
对象本身在任何地方都无法访问(公开或私有)。相反,只能访问从cycler
对象创建的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()
这不是唯一的方法,但在这种情况下比事先获取绘制线条的颜色更清晰。
line, = ax.plot(x, y)
,然后使用line.get_color()
来获取之前绘制线条的颜色。 - Joe Kingtonax._get_lines.color_cycle
不存在了? - endolithax._get_lines.prop_cycler
,你可以使用类似以下结构来构建:如果 ax._get_lines._prop_keys
中包含 'color',那么接下来使用 next(ax._get_lines.prop_cycler)['color']
来执行与答案中所建议的 color_cycle
相同的操作。我不确定是否可以仅获取颜色的可迭代对象,需要进一步探索。 - J Richard Snape以下是一种在1.5中有效的方法,希望它是兼容未来的,因为它不依赖于前缀带有下划线的方法:
colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]
这将为您提供按照当前样式定义的颜色列表。
_get_lines
已经更改。您现在需要在Python 2或3中使用next(ax._get_lines.prop_cycler)['color']
(或Python 2中的ax._get_lines.prop_cycler.next()['color']
),以从颜色循环中获取下一个颜色。_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>
r c m y k b g r c m
#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
color_cycle
已被弃用,因此您必须使用prop_cycler
,但是Andi的解决方法(ax._get_lines.prop_cycler.next()['color']
)对我来说返回了以下错误:
对我有效的代码是:AttributeError: 'itertools.cycle' object has no attribute 'next'
next(ax._get_lines.prop_cycler)
,这实际上与@joe-kington的原始响应相差不远。style.use('ggplot')
,所以需要一种使颜色正确循环的方法。可能有更简单/更好的方法来做到这一点,所以请随时纠正我。next(ax._get_lines.prop_cycler)
作为一种可能的替代方案。 - UmNyobenext(ax._get_lines.prop_cycler)
实际上改变颜色循环器的状态? - MB-Fprop_cycler
的状态。如果您阅读此问题的已接受答案,您将看到没有办法访问prop_cycler
的状态,因为它是可迭代的,必须改变其状态。 - Carson由于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
>>> list_from_cycle(ax._get_lines.prop_cycler)
[{'color': 'r'}, {'color': 'g'}, {'color': 'b'}]
>>> list_from_cycle(ax._get_lines.color_cycle)
['r', 'g', 'b']
ax1.lines[-1].get_color()
即可。如何访问颜色(和完整样式)循环?
当前状态存储在ax._get_lines.prop_cycler
中。
没有内置方法来公开通用的itertools.cycle
的“基本列表”,特别是对于ax._get_lines.prop_cycler
(见下文)。
我在这里发布了一些函数以获取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']
获取当前颜色而不改变循环的状态。
简而言之
颜色(和完整样式)循环存储在哪里?
样式循环存储在两个不同的位置,一个是用于默认,另一个是用于当前轴(假设import matplotlib.pyplot as plt
和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'>
默认循环可能有几个键(属性)要循环,而且只能获取颜色:
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']
甚至可以在定义了custom_prop_cycler
之后,更改给定axes
使用的cycler
。
ax.set_prop_cycle(custom_prop_cycler)
但是没有内置的方法来公开泛型 itertools.cycle
的“基础列表”,特别是针对 ax._get_lines.prop_cycler
。
我已经遇到过这个问题很多次了。
这是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()
_get_lines
属性上有一个get_next_color()
方法:import from matplotlib import pyplot as plt
fig, ax = plt.subplots()
next_color = ax._get_lines.get_next_color()
get_next_color()
返回一个 HTML 颜色字符串,并推进颜色循环迭代器。