获取matplotlib颜色循环状态

mwa*_*kom 84 python matplotlib

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

>>> plot(x1, y1)
>>> plot(x2, y2)
>>> state = get_cycle_state()
>>> print state
2
Run Code Online (Sandbox Code Playgroud)

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

Joe*_*ton 99

访问颜色循环迭代器

没有"面向用户"(又称"公共")方法来访问底层迭代器,但您可以通过"私有"(按惯例)方法访问它.但是,如果iterator不改变它,你就无法获得状态.

设置颜色循环

快速旁白:您可以通过多种方式设置颜色/属性循环(例如ax.set_color_cycle,版本<1.5或ax.set_prop_cycler> = 1.5).请查看此处1.5或更高版本示例,或此处上一个样式.

访问底层迭代器

但是,虽然没有面向公共的方法来访问iterable,但您可以ax通过_get_lineshelper类实例访问给定轴对象(). 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时,这已经改为使用cycler,并且调用了iterable 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']
Run Code Online (Sandbox Code Playgroud)

你无法查看状态 iterator

但是,这个对象是"裸露的" iterator.我们可以很容易地得到下一个项目(例如next_color = next(color_cycle),但这意味着之后的下一个颜色将被绘制.通过设计,没有办法获得迭代器的当前状态而不改变它.

v1.5或更大,这将是很好得到cycler多数民众赞成使用,我们可以推断其当前状态的对象.但是,cycler对象本身无法在任何地方(公开或私下)访问.相反,只能访问itertools.cyclecycler对象创建的实例.无论哪种方式,都无法进入颜色/属性循环器的基础状态.

改为匹配先前绘制的项目的颜色

在你的情况下,听起来你想要匹配刚绘制的东西的颜色.不要试图确定颜色/属性是什么,而是根据绘制内容的属性设置新项目的颜色/等.

例如,在你描述的情况下,我会做这样的事情:

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()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

这不是唯一的方法,但它比在此情况下尝试获取绘制线的颜色更清洁.

  • 如果您只是想匹配特定对象的颜色,您可以随时获取其颜色.例如`line,= ax.plot(x,y)`然后使用`line.get_color()`来获得先前绘制的线的颜色. (11认同)
  • 我认为(近)等价是一个可迭代的`ax._get_lines.prop_cycler`你可以在ax._get_lines._prop_keys中有一个类似`if'color'的结构:`后跟`next(ax._get_lines.prop_cycler)['我相信,颜色']`与答案中的'color_cycle`相同.我不确定你是否可以获得只有颜色的迭代,我需要探索更多. (6认同)
  • 似乎`ax._get_lines.color_cycle`在1.5中不再存在? (2认同)

Mik*_*tis 18

这是一种在1.5中工作的方式,希望能够面向未来,因为它不依赖于下划线前面的方法:

colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]
Run Code Online (Sandbox Code Playgroud)

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

  • 这就是我所需要的,谢谢。适用于 matplotlib 3.4.3。 (2认同)
  • 适用于 matplotlib 3.5.2 (2认同)

And*_*ndi 15

注意:最新版本的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,它可能在未来以不向后兼容的方式再次改变.


ary*_*naq 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,
Run Code Online (Sandbox Code Playgroud)

得到:

<itertools.cycle object at 0x034CB288>
r c m y k b g r c m
Run Code Online (Sandbox Code Playgroud)

这是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()
Run Code Online (Sandbox Code Playgroud)

安慰

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
Run Code Online (Sandbox Code Playgroud)

旋转颜色


小智 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'). 可能有更简单/更好的方法来做到这一点,所以请随时纠正我。