Можно ли запросить текущее состояние цветового цикла matplotlib? Другими словами, есть ли функция, get_cycle_state
которая будет вести себя следующим образом?
>>> plot(x1, y1)
>>> plot(x2, y2)
>>> state = get_cycle_state()
>>> print state
2
Где я ожидаю, что состояние будет индексом следующего цвета, который будет использоваться в графике. В качестве альтернативы, если бы он вернул следующий цвет («r» для цикла по умолчанию в приведенном выше примере), это тоже было бы хорошо.
python
matplotlib
Мваском
источник
источник
Ответы:
Доступ к итератору цветового цикла
Не существует "ориентированного на пользователя" (также известного как "общедоступный") метода для доступа к базовому итератору, но вы можете получить к нему доступ через "частные" (по соглашению) методы. Однако вы не можете получить состояние,
iterator
не изменив его.Установка цветового цикла
Небольшое отступление: вы можете установить цикл цвет / свойство различными способами (например,
ax.set_color_cycle
в версиях <1.5 илиax.set_prop_cycler
в> = 1.5). Взгляните на пример здесь для версии 1.5 или выше или на предыдущий стиль здесь .Доступ к базовому итератору
Однако, хотя нет общедоступного метода для доступа к итерируемому объекту, вы можете получить к нему доступ для данного объекта осей (
ax
) через_get_lines
экземпляр вспомогательного класса.ax._get_lines
- это прикосновение, название которого сбивает с толку, но это закулисный механизм, который позволяетplot
команде обрабатывать все странные и разнообразные способыplot
вызова. Среди прочего, это то, что отслеживает, какие цвета назначать автоматически. Точно так жеax._get_patches_for_fill
можно контролировать циклическое переключение цветов заливки по умолчанию и свойств патча.В любом случае, итеративный цветовой цикл предназначен
ax._get_lines.color_cycle
для линий иax._get_patches_for_fill.color_cycle
для участков. В matplotlib> = 1.5 это было изменено, чтобы использоватьcycler
библиотеку , и итерация вызывается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
объект уровня In или выше, поскольку мы можем вывести его текущее состояние. Однако самcycler
объект нигде недоступен (публично или приватно). Вместо этого доступен толькоitertools.cycle
экземпляр, созданный изcycler
объекта. В любом случае, нет никакого способа добраться до базового состояния циклера цвета / свойства.Вместо этого сопоставьте цвет ранее нанесенного элемента
В вашем случае это похоже на то, что вы хотите сопоставить цвет с тем, что только что было нанесено. Вместо того, чтобы пытаться определить, каким будет цвет / свойство, установите цвет / и т. Д. Вашего нового элемента на основе свойств того, что отображается на графике.
Например, в описанном вами случае я бы сделал что-то вроде этого:
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()
Это не единственный способ, но в данном случае он чище, чем попытка получить цвет нанесенной линии заранее.
источник
line, = ax.plot(x, y)
а затем используйте,line.get_color()
чтобы получить цвет ранее нанесенной линии.ax._get_lines.color_cycle
в 1.5 уже нет?ax._get_lines.prop_cycler
вас может быть такая конструкция,if 'color' in ax._get_lines._prop_keys:
за которойnext(ax._get_lines.prop_cycler)['color']
следует выполнение эквивалента того, что предлагаетсяcolor_cycle
в ответе, я считаю. Я не уверен, можно ли получить итерацию только по цветам, мне нужно изучить больше.Вот способ, который работает в версии 1.5, который, мы надеемся, будет перспективным, поскольку он не полагается на методы, добавленные с подчеркиванием:
colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]
Это даст вам список цветов, определенных для текущего стиля.
источник
Примечание: в последних версиях 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, он может снова измениться не обратно совместимым образом в будущем.источник
Конечно, это сработает.
#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.cycle
Изменить: Спасибо за комментарий, похоже, что итератор скопировать невозможно. Идея заключалась бы в том, чтобы сбросить полный цикл и отслеживать, какое значение вы используете, позвольте мне вернуться к этому.
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
источник
Я просто хочу добавить к тому, что @Andi сказал выше. Поскольку
color_cycle
он устарел в matplotlib 1.5, вы должны использоватьprop_cycler
, однако, решение Andi (ax._get_lines.prop_cycler.next()['color']
) вернуло мне эту ошибку:Код, который работал у меня, был:
next(ax._get_lines.prop_cycler)
что на самом деле недалеко от оригинального ответа @joe-kington.Лично я столкнулся с этой проблемой, когда делал ось twinx (), которая сбрасывала цветовой цикл. Мне нужен был способ заставить цвета циклически правильно циклиться, потому что я использовал
style.use('ggplot')
. Возможно, есть более простой / лучший способ сделать это, так что не стесняйтесь поправлять меня.источник
next(ax._get_lines.prop_cycler)
- это возможная альтернатива.next(ax._get_lines.prop_cycler)
самом деле изменял состояние цветового циклера?prop_cycler
. Если вы прочитаете принятый ответ на этот вопрос, вы увидите, что нет способа получить доступ к состояниюprop_cycler
без изменения его состояния, потому что оно является итеративным.Поскольку используется 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 <1.5:
>>> list_from_cycle(ax._get_lines.color_cycle) ['r', 'g', 'b']
источник
Самый простой способ, который я мог найти, не выполняя весь цикл через циклер, - это
ax1.lines[-1].get_color()
.источник
В matplotlib версии 2.2.3 для свойства есть
get_next_color()
метод_get_lines
:import from matplotlib import pyplot as plt fig, ax = plt.subplots() next_color = ax._get_lines.get_next_color()
get_next_color()
возвращает цветовую строку HTML и продвигает итератор цветового цикла.источник
Как получить доступ к циклу цвета (и полного стиля)?
Текущее состояние сохраняется в
ax._get_lines.prop_cycler
. Не существует встроенных методов для отображения «базового списка» для универсальногоitertools.cycle
, и в частности дляax._get_lines.prop_cycler
(см. Ниже).Я разместил здесь несколько функций, чтобы получить информацию о
itertools.cycle
. Тогда можно было бы использоватьstyle_cycle = ax._get_lines.prop_cycler curr_style = get_cycle_state(style_cycle) # <-- my (non-builtin) function curr_color = curr_style['color']
чтобы получить текущий цвет без изменения состояния цикла .
TL; DR
Где хранится цикл цвета (и полного стиля)?
Цикл стилей хранится в двух разных местах, одно по умолчанию , а другое для текущих осей (при условии, что
import matplotlib.pyplot as plt
иax
является обработчиком оси):default_prop_cycler = plt.rcParams['axes.prop_cycle'] current_prop_cycle = ax._get_lines.prop_cycler
Обратите внимание, что у них разные классы. По умолчанию используется «настройка базового цикла», и он не знает ни о каком текущем состоянии для каких-либо осей, в то время как текущий знает о цикле, которому следует следовать, и его текущем состоянии:
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'>
Цикл по умолчанию может иметь несколько ключей (свойств) для цикла, и можно получить только цвета:
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']
Можно даже изменить
cycler
использование для данногоaxes
, после определения этогоcustom_prop_cycler
с помощьюНо не существует встроенных методов для отображения «базового списка» для универсального
itertools.cycle
, и в частности дляax._get_lines.prop_cycler
.источник