Get matplotlib color cycle state

Is it possible to query the current state of the matplotlib color cycle? In other words, is there a get_cycle_state function that will behave as follows?

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

Where I expect the state to be the index of the next color to be used in the plot. Alternatively, if he returned the next color ("r" for the default loop in the example above), that would be fine too.

+78
python matplotlib
Dec 12 '12 at 1:50
source share
7 answers

Access to the color loop iterator

There is no "user-oriented" (otherwise called "public") method for accessing the base iterator, but you can access it through the "private" (by convention) methods. However, you cannot get the iterator state without changing it.

Color cycle setting

Quick side: you can set the color / cycle of properties in various ways (for example, ax.set_color_cycle in versions <1.5 or ax.set_prop_cycler in> = 1.5). Take a look at the example here for version 1.5 or higher or the previous style here .

Access to the base iterator

However, despite the lack of open access to this process, you can access it for a given object of axes ( ax ) through _get_lines auxiliary class _get_lines . ax._get_lines is a touch vaguely named, but it's a behind-the-scenes mechanism that allows the plot command to handle all the odd and varied ways of plotting. Among other things, this is what tracks which colors are automatically assigned. Similarly, ax._get_patches_for_fill controls the cyclic use of the default fill colors and patch properties.

Anyway, the iterable loop cycle is ax._get_lines.color_cycle for strings and ax._get_patches_for_fill.color_cycle for patches. On Matplotlib> = 1.5, this has changed to use the cycler library , and the iteration is called prop_cycler instead of color_cycle and gives dict properties instead of just color.

In general, you would do something like:

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

You cannot view the status of iterator

However, this object is a bare iterator . We can easily get the next element (for example, next_color = next(color_cycle) , but this means that the next color will be displayed after that. By design, there is no way to get the current state of the iterator without changing it.

In v1.5 or higher, it would be nice to get the cycler object cycler , since we could infer its current state. However, the cycler object cycler not available (publicly or privately) anywhere. Instead, only the itertools.cycle instance created from the cycler object is available. In any case, there is no way to get to the ground state of the color / cycler property.

Match the color of a previously drawn object instead

In your case, it sounds as if you want to match the color of what was simply built. Instead of deciding what the color / property will be, set the / etc color of your new element based on the properties of what is plotted.

For example, in the case you described, I would do something like this:

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

enter image description here

This is not the only way, but it is cleaner than trying to get the color of the drawn line before that, in this case.

+88
Dec 12
source share

Note. In recent versions of matplotlib (> = 1.5) _get_lines has changed. Now you need to use next(ax._get_lines.prop_cycler)['color'] in Python 2 or 3 (or ax._get_lines.prop_cycler.next()['color'] in Python 2 ) to get the next color from the color loop .

If possible, use a more direct approach, shown at the bottom of @ joe-kington's answer. Since _get_lines not _get_lines the API, it may change in an incompatible way in the future.

+14
Nov 09 '15 at 11:56
source share

Here is a method that works in 1.5, which we hope will be promising since it does not rely on methods added with underscores:

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

This will give you a list of colors defined for the current style.

+12
Jul 23 '16 at 6:47
source share

Of course, this will be done.

 #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, 

gives:

 <itertools.cycle object at 0x034CB288> rcmykbgrcm 

Here is the itertools function in which matplotlib uses itertools.cycle

Edit: thanks for the comment, it seems like iterating is impossible to copy. The idea would be to reset the full loop and keep track of what value you are using, let me get back to that.

Edit2: Well, this will give you the next color and create a new iterator that will behave as if the next one was not called. This does not preserve the order of coloring, just the next color value, I leave it to you.

This gives the following conclusion: note that the steepness of the graph corresponds to the index, for example, the first g is the lowest graph, etc.

 #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() 

Console

 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 

Rotate color

+6
Dec 12 '12 at 2:20
source share

I just want to add what @Andi said above. Since color_cycle deprecated in matplotlib 1.5, you should use prop_cycler , however Andi's solution ( ax._get_lines.prop_cycler.next()['color'] ) returned this error to me:

AttributeError: object 'itertools.cycle' does not have attribute 'next'

The code that worked for me was: next(ax._get_lines.prop_cycler) , which is actually just around the corner from the original @ joe-kington answer.

Personally, I ran into this problem when creating the doublex () axis, which reset the color cycle. I needed to adjust the color correctly because I used style.use('ggplot') . There may be an easier / better way to do this, so feel free to correct me.

+4
Dec 15 '15 at 17:20
source share

Since matplotlib uses itertools.cycle , we can actually look at the entire color cycle, and then restore the iterator to its previous state:

 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 

This should return the list without changing the state of the iterator.

Use it with matplotlib> = 1.5:

 >>> list_from_cycle(ax._get_lines.prop_cycler) [{'color': 'r'}, {'color': 'g'}, {'color': 'b'}] 

or with matplotlib <1.5:

 >>> list_from_cycle(ax._get_lines.color_cycle) ['r', 'g', 'b'] 
+1
Sep 22 '16 at 8:38
source share

In Matplotlib version 2.2.3 there is a get_next_color() method on the _get_lines property:

 import from matplotlib import pyplot as plt fig, ax = plt.subplots() next_color = ax._get_lines.get_next_color() 

get_next_color() returns an HTML color string and promotes the color loop iterator.

0
Dec 10 '18 at 13:52
source share



All Articles