Get matplotlib color cycle state

后端 未结 9 1564
慢半拍i
慢半拍i 2020-11-27 10:36

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

相关标签:
9条回答
  • 2020-11-27 11:05

    Note: In the latest versions of matplotlib (>= 1.5) _get_lines has changed. You now 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 cycle.

    Wherever possible use the more direct approach shown in the lower part of @joe-kington's answer. As _get_lines is not API-facing it might change again in a not backward compatible manner in the future.

    0 讨论(0)
  • 2020-11-27 11:06

    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 advances the color cycle iterator.

    0 讨论(0)
  • 2020-11-27 11:14

    Sure, this will do it.

    #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>
    r c m y k b g r c m
    

    Here is the itertools function that matplotlib uses itertools.cycle

    Edit: Thanks for the comment, it seems that it is not possible to copy an iterator. An idea would be to dump a full cycle and keep track of which value you are using, let me get back on that.

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

    This gives the following output, notice that steepness in the plot corresponds to index, eg first g is the bottomest graph and so on.

    #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

    0 讨论(0)
  • 2020-11-27 11:16

    How to access the color (and complete style) cycle?

    The current state is stored in ax._get_lines.prop_cycler. There are no built-in methods to expose the "base list" for a generic itertools.cycle, and in particular for ax._get_lines.prop_cycler (see below).

    I have posted here a few functions to get info on a itertools.cycle. One could then use

    style_cycle = ax._get_lines.prop_cycler
    curr_style = get_cycle_state(style_cycle)  # <-- my (non-builtin) function
    curr_color = curr_style['color']
    

    to get the current color without changing the state of the cycle.


    TL;DR

    Where is the color (and complete style) cycle stored?

    The style cycle is stored in two different places, one for the default, and one for the current axes (assuming import matplotlib.pyplot as plt and ax is an axis handler):

    default_prop_cycler = plt.rcParams['axes.prop_cycle']
    current_prop_cycle = ax._get_lines.prop_cycler
    

    Note these have different classes. The default is a "base cycle setting" and it does not know about any current state for any axes, while the current knows about the cycle to follow and its current state:

    print('type(default_prop_cycler) =', type(default_prop_cycler))
    print('type(current_prop_cycle) =', type(current_prop_cycle))
    
    []: type(default_prop_cycler) = <class 'cycler.Cycler'>
    []: type(current_prop_cycle) = <class 'itertools.cycle'>
    

    The default cycle may have several keys (properties) to cycle, and one can get only the colors:

    print('default_prop_cycler.keys =', default_prop_cycler.keys)
    default_prop_cycler2 = plt.rcParams['axes.prop_cycle'].by_key()
    print(default_prop_cycler2)
    print('colors =', default_prop_cycler2['color'])
    
    []: default_prop_cycler.keys = {'color', 'linestyle'}
    []: {'color': ['r', 'g', 'b', 'y'], 'linestyle': ['-', '--', ':', '-.']}
    []: colors = ['r', 'g', 'b', 'y']
    

    One could even change the cycler to use for a given axes, after defining that custom_prop_cycler, with

    ax.set_prop_cycle(custom_prop_cycler)
    

    But there are no built-in methods to expose the "base list" for a generic itertools.cycle, and in particular for ax._get_lines.prop_cycler.

    0 讨论(0)
  • 2020-11-27 11:20

    The simplest way possible I could find without doing the whole loop through the cycler is ax1.lines[-1].get_color().

    0 讨论(0)
  • 2020-11-27 11:21

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

    AttributeError: 'itertools.cycle' object has no attribute 'next'

    The code that worked for me was: next(ax._get_lines.prop_cycler), which actually isn't far off from @joe-kington's original response.

    Personally, I ran into this problem when making a twinx() axis, which reset the color cycler. I needed a way to make the colors cycle correctly because I was using style.use('ggplot'). There might be an easier/better way to do this, so feel free to correct me.

    0 讨论(0)
提交回复
热议问题