获取matplotlib颜色循环状态

时间:2012-12-12 01:50:07

标签: python matplotlib

是否可以查询matplotlib颜色循环的当前状态?换句话说,是否有一个函数get_cycle_state将按以下方式运行?

>>> plot(x1, y1)
>>> plot(x2, y2)
>>> state = get_cycle_state()
>>> print state
2

我希望状态是将在绘图中使用的下一种颜色的索引。或者,如果它返回下一个颜色(上例中默认循环的“r”),那也没关系。

10 个答案:

答案 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 greaterprevious 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()

enter image description here

这不是唯一的方法,但在这种情况下,它比在前手绘制线条的颜色更干净。

答案 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

Rotate color

答案 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 的最小工作示例。 enter image description here

代码

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()