96

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

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

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

4

10 回答 10

120

访问颜色循环迭代器

没有“面向用户”(又名“公共”)方法来访问底层迭代器,但您可以通过“私有”(按照约定)方法访问它。iterator但是,如果不更改它,您将无法获得状态。

设置颜色循环

顺便说一句:您可以通过多种方式设置颜色/属性循环(例如ax.set_color_cycle,在 <1.5 或ax.set_prop_cycler>=1.5 的版本中)。请查看此处的示例,了解版本 1.5 或更高版本,或查看以前的样式

访问底层迭代器

但是,虽然没有面向公众的方法来访问可迭代对象,但您可以通过帮助程序类实例 为给定的轴对象 ( ax)访问它。名称有点令人困惑,但它是幕后机器,它允许命令处理所有可以调用的奇怪和多样的方式。除此之外,它还可以跟踪自动分配的颜色。同样,可以通过默认填充颜色和补丁属性来控制循环。_get_linesax._get_linesplotplotax._get_patches_for_fill

无论如何,可迭代的颜色循环ax._get_lines.color_cycle适用于线条和ax._get_patches_for_fill.color_cycle补丁。在 matplotlib >=1.5 上,这已更改为使用cyclerlibrary,并且调用 iterableprop_cycler而不是color_cycle并产生 a dictof 属性而不是仅颜色。

总而言之,你会做这样的事情:

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),但这意味着之后的下一个颜色将被绘制。根据设计,没有办法在不更改迭代器的情况下获取它的当前状态。

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

在此处输入图像描述

在这种情况下,这不是唯一的方法,但它比尝试事先获取绘制线的颜色更干净。

于 2012-12-12T02:24:48.283 回答
30

这是一种适用于 1.5 的方法,它有望在未来得到验证,因为它不依赖于带有下划线的方法:

colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]

这将为您提供按当前样式定义的颜色列表。

于 2016-07-23T06:47:35.213 回答
18

注意:在最新版本的 matplotlib (>= 1.5)_get_lines中发生了变化。您现在需要next(ax._get_lines.prop_cycler)['color']在 Python 2 或 3(或ax._get_lines.prop_cycler.next()['color']Python 2中)使用从颜色循环中获取下一个颜色。

尽可能使用@joe-kington 答案下部显示的更直接的方法。由于_get_lines它不是面向 API 的,因此将来可能会以不向后兼容的方式再次更改。

于 2015-11-09T11:56:30.150 回答
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:好的,这将为您提供下一种颜色并创建一个新的迭代器,其行为就像未调用 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

旋转颜色

于 2012-12-12T02:20:38.827 回答
5

我只想补充上面@Andi 所说的内容。由于color_cycle在 matplotlib 1.5 中已弃用,因此您必须使用prop_cycler,但是,Andi 的解决方案 ( ax._get_lines.prop_cycler.next()['color']) 为我返回了此错误:

AttributeError:“itertools.cycle”对象没有属性“next”

对我有用的代码是: next(ax._get_lines.prop_cycler),实际上与@joe-kington 的原始响应相差不远。

就个人而言,我在制作 twinx() 轴时遇到了这个问题,它重置了颜色循环器。我需要一种使颜色正确循环的方法,因为我使用的是style.use('ggplot'). 可能有更简单/更好的方法来做到这一点,所以请随时纠正我。

于 2015-12-15T17:20:45.030 回答
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 >= 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']
于 2016-09-22T08:38:25.553 回答
1

在不通过循环器进行整个循环的情况下,我能找到的最简单的方法是ax1.lines[-1].get_color().

于 2019-12-26T20:30:03.463 回答
0

如何访问颜色(和完整的样式)循环?

当前状态存储在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']

在不改变循环状态的情况下获取当前颜色。


TL;博士

颜色(和完整的样式)循环存储在哪里?

样式循环存储在两个不同的位置,一个用于default,一个用于当前轴(假设import matplotlib.pyplot as pltax是轴处理程序):

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']

在定义之后,甚至可以更改cycler用于给定的axescustom_prop_cycler

ax.set_prop_cycle(custom_prop_cycler)

但是没有内置方法可以公开泛型的“基本列表” itertools.cycle,尤其是ax._get_lines.prop_cycler.

于 2019-12-22T08:32:43.433 回答
-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 颜色字符串,并推进颜色循环迭代器。

于 2018-12-10T13:52:57.310 回答
-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()
于 2021-03-04T09:39:51.490 回答