python - Cycle colors when plotting in matplotlib: Tracking state on a per-instance basis -
i'm trying build simple state-tracking function axes instance in matplotlib. every time create new axes object (either directly or through other functions subplots()
), want instance have bound method, a.next_color()
, can use cycle through colors create new lines add axes. wrote this:
def set_color_sequence(colors = ['r', 'g', 'b', 'c', 'm', 'y']): = [0] def cf(self): i[0] += 1 return colors[(i[0]-1) % len(colors)] return cf
and thought being clever adding parent class:
plt.axes.next_color = set_color_sequence()
the problem state variable i
seems shared all axes
instances, instead of each new instance having own state. what's elegant way ensure new instances have own state tracking function? (btw, i'd without modifying original matplotlib code.)
your existing function will work provided assign next_color
attribute instance of axes
rather class itself.
first of all, set_color_sequence
implementing generator in roundabout way. simplify things, can achieve same thing in 1 line using itertools.cycle
:
from itertools import cycle ... axes_instance.next_color = cycle(['r', 'g', 'b', 'c', 'm', 'y']).next
in fact, way matplotlib keeps track of in color cycle. example, if take @ instance of matplotlib.axes._subplots.axessubplot
see has attribute _get_lines.color_cycle
, itertools.cycle
(try calling color_cycle.next()
).
now take @ these 2 examples:
class myclass1(object): # next_color attribute of *class itself* next_color = cycle(['r', 'g', 'b', 'c', 'm', 'y']).next class myclass2(object): def __init__(self): # next_color attribute of *this instance* of class self.next_color = cycle(['r', 'g', 'b', 'c', 'm', 'y']).next
in first case, happens assignment
next_color = cycle(['r', 'g', 'b', 'c', 'm', 'y]).next
gets evaluated once , once, when class first imported. means whenever create new instance of myclass1
, next_color
attribute point @ exact same itertools.cycle
instance, , therefore instances of myclass1
share common state:
a = myclass1() b = myclass1() print a.next_color b.next_color # true print a.next_color(), a.next_color(), b.next_color() # r g b
however, __init__
method gets called again , again whenever new instance of class being created. consequence, every instance of myclass2
gets own itertools.cycle
, , therefore own state:
a = myclass2() b = myclass2() print a.next_color b.next_color # false print a.next_color(), a.next_color(), b.next_color() # r g r
if goal subclass plt.axes
, need put assignment somewhere called each new instance of subclass (probably in __init__
). however, if want add method existing instance literally need is:
axes_instance.next_color = get_color_sequence()
Comments
Post a Comment