python种颜色循环_关于python:在matplotlib中绘制时的循环颜色:基于每个实例的跟踪状态...

我正在尝试为Matplotlib中的Axes实例构建一个简单的状态跟踪功能。 每次我创建一个新的axes对象(直接或通过其他功能,例如subplots())时,我都希望实例具有一个绑定方法a.next_color(),当我创建要添加的新行时,可以使用该方法在颜色之间循环 到轴。 我写了这样的东西:

1

2

3

4

5

6def set_color_sequence(colors = ['r', 'g', 'b', 'c', 'm', 'y']):

i = [0]

def cf(self):

i[0] += 1

return colors[(i[0]-1) % len(colors)]

return cf

并且以为我很聪明,可以将其添加到父类中:

1plt.Axes.next_color = set_color_sequence()

问题在于状态变量i似乎由所有Axes实例共享,而不是每个新实例都具有自己的状态。 确保所有新实例具有自己的状态跟踪功能的一种优雅方法是什么? (顺便说一句,我想这样做而不修改原始的matplotlib代码。)

你可以继承它吗? class MyAxes(plt.Axes): def next_color(self): ...

也许这会有所帮助? 另外,为什么不创建一个单独的对象/函数而不是附加一个需要手动调用的方法(假设您不进一步修改类)呢?

matplotlib已经有这样的东西。给定ax1一个AxesSubplot实例(或任何派生Axes的东西),您可以使用_get_lines访问线属性。这包括prop_cycler,可以使用以下命令覆盖它:

1ax2._get_lines.prop_cycler = ax1._get_lines.prop_cycler

例如:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22# Generate some data

x = linspace(-10, 10)

y_lin = 2*x

y_quad = x**2

# Create empty axes

_, ax1 = subplots()

# Plot linear

l1 = ax1.plot(y_lin)

ax1.set_ylabel('linear', color=l1[0].get_color())

ax1.tick_params('y', colors=l1[0].get_color())

# Generate secondary y-axis

ax2 = ax1.twinx()

# Make sure that plots on ax2 continue color cycle

ax2._get_lines.prop_cycler = ax1._get_lines.prop_cycler

# Plot quadratic

l2 = ax2.plot(y_quad)

ax2.set_ylabel('quadratic', color=l2[0].get_color())

ax2.tick_params('y', colors=l2[0].get_color())

哪个输出:

MdqdA.png

省略ax2._get_lines.prop_cycler = ax1._get_lines.prop_cycler可以使我们:

LUROD.png

注意:如果您使用%pylab inline魔术在jupyter(或nteract)中工作(因此您将无法直接访问matplotlib.pyplot模块)。所以像plt.Axes这样的东西有点麻烦。

AMacK的评论使我想到了一个简单的解决方案:

1

2

3def next_color(self):

return next(self._get_lines.color_cycle)

plt.Axes.next_color = next_color

这没有我上面概述的自定义颜色序列行为,但是确实获得了我在简洁简洁的代码中正在寻找的每个实例的行为。 (如果我想生成自定义序列,大概可以直接覆盖color_cycle迭代器。)

好的,很公平,但是为什么不直接调用self._get_lines.color_cycle.next()? 另外,虽然可以覆盖color_cycle,但请记住,您必须要么基于每个实例执行此操作(否则必须子类plt.Axes),以使每个实例具有自己的状态。

如果您将next_color属性分配给

Axes的实例,而不是类本身。

首先,用

set_color_sequence,您基本上是在实现

回旋处的发电机。至

简化事情,我们可以使用

itertools.cycle:

1

2

3from itertools import cycle

...

axes_instance.next_color = cycle(['r', 'g', 'b', 'c', 'm', 'y']).next

实际上,这就是matplotlib跟踪其颜色位置的方式

周期。例如,如果您查看一个实例

matplotlib.axes._subplots.AxesSubplot,您将看到它具有属性

_get_lines.color_cycle,它是一个itertools.cycle(尝试调用

color_cycle.next())。

现在看下面两个例子:

1

2

3

4

5

6

7

8

9

10

11

12class MyClass1(object):

# next_color is an attribute of the *class itself*

next_color = cycle(['r', 'g', 'b', 'c', 'm', 'y']).next

class MyClass2(object):

def __init__(self):

# next_color is an attribute of *this instance* of the class

self.next_color = cycle(['r', 'g', 'b', 'c', 'm', 'y']).next

在第一种情况下,发生的情况是分配

1next_color = cycle(['r', 'g', 'b', 'c', 'm', 'y]).next

首次导入该类时,仅一次评估一次。这表示

每当您创建MyClass1的新实例时,其next_color

属性将指向完全相同的itertools.cycle实例,并且

因此MyClass1的所有实例将共享一个公共状态:

1

2

3

4

5

6

7

8a = MyClass1()

b = MyClass1()

print a.next_color is b.next_color

# True

print a.next_color(), a.next_color(), b.next_color()

# r g b

但是,每当一个新的__init__方法被一次又一次地调用

该类的实例正在创建。结果,每个MyClass2实例都会

它自己的itertools.cycle,因此它是自己的状态:

1

2

3

4

5

6

7

8a = MyClass2()

b = MyClass2()

print a.next_color is b.next_color

# False

print a.next_color(), a.next_color(), b.next_color()

# r g r

如果您的目标是子类plt.Axes,则需要放置您的作业

子类的每个新实例都会调用它的地方

(可能在__init__中)。但是,如果您只想添加此内容

现有实例的方法,那么您实际上需要做的就是:

1axes_instance.next_color = get_color_sequence()

感谢您在此处阐明问题。 接受此答案是因为它提供了两种出色的策略-每个实例的子类化和分配。 我在回答问题时采用了该策略,因为(a)它的简洁性和(b)可以应用在快速设置脚本中,而无需再考虑了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值