我试图在Matplotlib中为Axes实例构建一个简单的状态跟踪函数。每次我创建一个新的轴对象(直接或通过其他函数,如subplots()
),我希望实例有一个绑定方法,a.next_color()
,我可以用来循环颜色,因为我创建要添加到轴的新行。我写了这样的话:
def 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
认为我把它添加到父类是聪明的:
plt.Axes.next_color = set_color_sequence()
问题是状态变量i
似乎由所有 Axes
实例共享,而不是每个新实例都有自己的实例州。确保所有新实例都有自己的状态跟踪功能的优雅方法是什么? (顺便说一句,我想在不修改原始matplotlib代码的情况下这样做。)
答案 0 :(得分:0)
如果您为next_color
属性分配了{{1>}属性,那么您现有的功能将
<{1}}的实例而不是类本身。
首先,有了
Axes
你基本上是在实施一个
generator以迂回的方式。至
简化事情,我们可以在一行中实现同样的事情
set_color_sequence
:
itertools.cycle
实际上,这是matplotlib跟踪颜色所在位置的方式
周期。例如,如果你看一个实例
from itertools import cycle
...
axes_instance.next_color = cycle(['r', 'g', 'b', 'c', 'm', 'y']).next
您会看到它具有该属性
matplotlib.axes._subplots.AxesSubplot
,_get_lines.color_cycle
(试着打电话
itertools.cycle
)。
现在看看这两个例子:
color_cycle.next()
在第一种情况下,发生的是分配
class 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
首次导入时,只进行一次评估。这意味着
每当您创建next_color = cycle(['r', 'g', 'b', 'c', 'm', 'y]).next
的新实例时,其MyClass1
属性将指向完全相同的next_color
实例,并且
因此itertools.cycle
的所有实例都将共享一个共同状态:
MyClass1
但是,每当有新的时候,a = 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
如果你的目标是继承a = 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__
答案 1 :(得分:0)
AMacK的评论让我得到了一个简单的解决方案:
def next_color(self):
return next(self._get_lines.color_cycle)
plt.Axes.next_color = next_color
这并没有我在上面概述的自定义颜色序列行为,但它确实获得了我在代码中寻找的实例行为,这些行为简洁明了。 (如果我想生成自定义序列,我可以直接覆盖color_cycle迭代器。)
答案 2 :(得分:0)
ax1
已经有类似的东西。给定AxesSubplot
Axes
的实例(或任何派生_get_lines
的实例),您可以使用prop_cycler
访问行属性。这包括ax2._get_lines.prop_cycler = ax1._get_lines.prop_cycler
,可以使用以下方法覆盖:
# 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())
例如:
ax2._get_lines.prop_cycler = ax1._get_lines.prop_cycler
哪个输出:
离开%pylab inline
让我们:
注意:如果您使用matplotlib.pyplot
魔法在jupyter(或nteract)中工作(因此您将无法直接访问plt.Axes
模块)。所以像bluebird
这样的东西有点麻烦。