Сброс цветового цикла в Matplotlib

Скажем, у меня есть данные о 3 торговых стратегиях, каждая из которых имеет транзакционные издержки и без них. Я хочу построить на тех же осях временные ряды каждого из 6 вариантов (3 стратегии * 2 торговые издержки). Я хотел бы, чтобы линии "с транзакционной стоимостью" были нанесены с alpha=1 а также linewidth=1 в то время как я хочу, чтобы "без трансакционных издержек" был нанесен на график с alpha=0.25 а также linewidth=5, Но я бы хотел, чтобы цвет был одинаковым для обеих версий каждой стратегии.

Я хотел бы что-то вроде:

fig, ax = plt.subplots(1, 1, figsize=(10, 10))

for c in with_transaction_frame.columns:
    ax.plot(with_transaction_frame[c], label=c, alpha=1, linewidth=1)

****SOME MAGIC GOES HERE TO RESET THE COLOR CYCLE

for c in no_transaction_frame.columns:
    ax.plot(no_transaction_frame[c], label=c, alpha=0.25, linewidth=5)

ax.legend()

Какой код следует поместить в указанную строку для сброса цветового цикла, чтобы он возвращался к началу при запуске второго цикла?

5 ответов

Решение

Вы можете сбросить цветовой цикл до исходного с помощью Axes.set_color_cycle. Глядя на код для этого, есть функция для выполнения реальной работы:

def set_color_cycle(self, clist=None):
    if clist is None:
        clist = rcParams['axes.color_cycle']
    self.color_cycle = itertools.cycle(clist

И метод на осях, который использует его:

def set_color_cycle(self, clist):
    """
    Set the color cycle for any future plot commands on this Axes.

    *clist* is a list of mpl color specifiers.
    """
    self._get_lines.set_color_cycle(clist)
    self._get_patches_for_fill.set_color_cycle(clist)

Это в основном означает, что вы можете вызвать set_color_cycle с None в качестве единственного аргумента, и он будет заменен циклом по умолчанию, найденным в rcParams['axes.color_cycle'].

Я попробовал это с помощью следующего кода и получил ожидаемый результат:

import matplotlib.pyplot as plt
import numpy as np

for i in range(3):
    plt.plot(np.arange(10) + i)

# for Matplotlib version < 1.5
plt.gca().set_color_cycle(None)
# for Matplotlib version >= 1.5
plt.gca().set_prop_cycle(None)

for i in range(3):
    plt.plot(np.arange(10, 1, -1) + i)

plt.show()

Вывод кода, показывающий функциональность сброса цветового цикла

В качестве ответа, данного @pelson, используется set_color_cycle и это устарело в Matplotlib 1.5, я подумал, что было бы полезно иметь обновленную версию его решения, используя set_prop_cycle:

import matplotlib.pyplot as plt
import numpy as np

for i in range(3):
    plt.plot(np.arange(10) + i)

plt.gca().set_prop_cycle(None)

for i in range(3):
    plt.plot(np.arange(10, 0, -1) + i)

plt.show()

Отметим также, что мне пришлось изменить np.arange(10,1,-1) в np.arange(10,0,-1), Первый дал массив только из 9 элементов. Вероятно, это связано с использованием разных версий Numpy. Мой 1.10.2.

РЕДАКТИРОВАТЬ: устранена необходимость использования rcParams, Спасибо @divenex за то, что указал на это в комментарии.

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

with sns.color_palette(n_colors=3):

    ax.plot(...)
    ax.plot(...)

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

Обратите внимание, что единственное, что на самом деле должно быть под with Блок это все, что вы делаете, чтобы создать Axes объект (т.е. plt.subplots, fig.add_subplot(), так далее.). Это просто из-за того, как работает сам цветовой цикл matplotlib.

Делать то, что вы конкретно хотите, "сбрасывать" цветовой цикл, возможно, но это хак, и я бы не стал делать это в любом виде производственного кода. Вот как это могло произойти:

f, ax = plt.subplots()
ax.plot(np.random.randn(10, 3))
ax._get_lines.color_cycle = itertools.cycle(sns.color_palette())
ax.plot(np.random.randn(10, 3), lw=5, alpha=.25)

Просто выберите ваши цвета и назначьте их списку, а затем, когда вы строите свои данные, выполняйте итерации по zip объект, содержащий ваш столбец и цвет, который вы хотите.

colors = ['red', 'blue', 'green']

for col, color in zip(colors, with_transaction_frame.columns):
    ax.plot(with_transaction_frame[col], label=col, alpha=1.0, linewidth=1.0, color=color)

for col, color in zip(no_transaction_frame.columns):
    ax.plot(no_transaction_frame[col], label=col, alpha=0.25, linewidth=5, color=color)

zip создает список, который объединяет элементы из каждого из ваших списков. Это позволяет вам легко перебирать и то и другое одновременно.

Вы можете получить цвета от морского бора как это: colors = sns.color_palette(), Ответ Ffisegydd тогда будет отлично работать. Вы также можете получить цвет для построения графика, используя оператор модуля / остатка (%): mycolor = colors[icolumn % len(colors], Я часто использую этот подход сам. Так что вы могли бы сделать:

for icol, column in enumerate(with_transaction_frame.columns): mycolor = colors[icol % len(colors] ax.plot(with_transaction_frame[col], label=col, alpha=1.0, color=mycolor)

Однако ответ Ффизегида может быть более "питоническим".

В дополнение к уже отличным ответам вы можете рассмотреть возможность использования цветовой карты:

import matplotlib.pyplot as plt
import numpy as np

cmap = plt.cm.viridis

datarange = np.arange(4)

for d in datarange:
    # generate colour by feeding float between 0 and 1 to colormap
    color = cmap(d/np.max(datarange)) 
    plt.plot(np.arange(5)+d, c=color)

for d in datarange:
    # generate colour by feeding float between 0 and 1 to colormap
    color = cmap(d/np.max(datarange))
    plt.plot(-np.arange(5)+d, c=color)

https://stackru.com/images/8c605fe73fbf97d365ee41707f5732ba3ea37627.png

Другие вопросы по тегам