Получить состояние цветового цикла matplotlib


можно ли запросить текущее состояние цветового цикла matplotlib? Другими словами есть ли функция get_cycle_state что будет вести себя следующим образом?

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

где я ожидаю, что состояние будет индексом следующего цвета, который будет использоваться в графике. Кроме того, если он вернул следующий цвет ("r" для цикла по умолчанию в приведенном выше примере), это тоже было бы хорошо.

6 76

6 ответов:

доступ к итератору цветового цикла

для доступа к базовому итератору нет метода" user-facing "(он же" public"), но вы можете получить к нему доступ через" частные " (по соглашению) методы. Однако, вы не можете получить состояние iterator без изменения.

настройка цветового цикла

Quick aside: вы можете установить цикл цвета/свойства различными способами (например,ax.set_color_cycle в версии ax.set_prop_cycler in > =1.5). Взгляните на пример для версии 1.5 или выше или предыдущий стиль здесь.

доступ к базовому итератор

однако, хотя нет открытого метода для доступа к iterable, вы можете получить доступ к нему для данного объекта axes (ax) через _get_lines экземпляр вспомогательного класса. ax._get_lines это прикосновение смутно названо, но это закулисный механизм, который позволяет plot команда для обработки всех нечетных и разнообразных способы, которые plot можно назвать. Среди прочего, это то, что отслеживает, какие цвета автоматически назначать. Точно так же есть ax._get_patches_for_fill для управления циклическим использованием цветов заливки по умолчанию и свойств патча.

во всяком случае, цикл цвета iterable ax._get_lines.color_cycle для строк и ax._get_patches_for_fill.color_cycle для исправления. На matplotlib >=1.5, это изменилось на использовать cycler библиотека, и iterable называется prop_cycler вместо color_cycle и получается dict of свойства, а не только цвет.

в общем, вы бы сделали что-то вроде:

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

вы не можете просмотреть состояние iterator

однако этот объект является "голым"iterator. Мы можем легко получить следующий элемент (например,next_color = next(color_cycle), но это значит, что следующий цвет после этого это то, что будет нанесено на график. По замыслу, нет никакого способа получить текущее состояние итератора без его изменения.

на v1.5 или выше было бы неплохо получить cycler объект, который используется, как мы могли бы сделать вывод о его текущем состоянии. Тем не менее,cycler сам объект не доступен (публично или в частном порядке) в любом месте. Вместо этого, только itertools.cycle экземпляр, созданный из

Примечание: В последних версиях matplotlib (>=1.5) _get_lines изменилось. Теперь вам нужно использовать next(ax._get_lines.prop_cycler)['color'] в Python 2 или 3 (или ax._get_lines.prop_cycler.next()['color'] на Python 2), чтобы получить следующий цвет из цветовой цикл.

везде, где это возможно, используйте более прямой подход, показанный в нижней части ответа @joe-kington. Как _get_lines не API-облицовка это может измениться снова в не обратно совместимым образом в будущем.

вот способ, который работает в 1.5, который, надеюсь, будет в будущем, поскольку он не зависит от методов, добавленных с подчеркиванием:

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

Это даст вам список цветов, определенных для настоящего стиля.

конечно, это сделает это.

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

выдает:

<itertools.cycle object at 0x034CB288>
r c m y k b g r c m

вот функция itertools, которую использует matplotlib itertools.цикл

Edit: Спасибо за комментарий, кажется, что невозможно скопировать итератор. Идея состояла бы в том, чтобы сбросить полный цикл и отслеживать, какое значение вы используете, позвольте мне вернуться к этому.

Edit2: хорошо, это даст вам следующий цвет и сделает новый итератор, который ведет себя так, как будто дальше не назывался. Это не сохраняет порядок окраски, просто следующее значение цвета, я оставляю это вам.

это дает следующий вывод, обратите внимание, что крутизна в графике соответствует индексу, например, первый g является самым нижним графом и так далее.

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

консоль

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

Я просто хочу добавить к тому, что @Andi сказал выше. Так как color_cycle является устаревшим в matplotlib 1.5, вы должны использовать prop_cycler, однако, решение Анди (ax._get_lines.prop_cycler.next()['color']) вернул эту ошибку для меня:

AttributeError: 'itertools.цикл 'объект не имеет атрибута 'next'

код, который работал для меня было: next(ax._get_lines.prop_cycler), что на самом деле не так далеко от первоначального ответа @joe-kington.

лично я столкнулся с этой проблемой при оформлении ось twinx (), которая сбрасывает цветовой Циклер. Мне нужен был способ сделать цикл цветов правильно, потому что я использовал style.use('ggplot'). Там может быть проще/лучше способ сделать это, так что не стесняйтесь, чтобы исправить меня.

так как matplotlib использует itertools.cycle мы можем фактически просмотреть весь цветовой цикл, а затем восстановить итератор в его предыдущее состояние:

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

это должно вернуть список без изменения состояния итератора.

используйте его с matplotlib > = 1.5:

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

или с matplotlib

>>> list_from_cycle(ax._get_lines.color_cycle)
['r', 'g', 'b']