создание более 20 уникальных цветов легенды с помощью matplotlib - PullRequest
42 голосов
/ 05 декабря 2011

Я строю 20 разных линий на одном графике, используя matplotlib. Я использую цикл for для построения и маркировки каждой строки своим ключом, а затем использую функцию легенды

for key in dict.keys():
    plot(x,dict[key], label = key)
graph.legend()

Но, используя этот способ, график повторяет много цветов в легенде. Можно ли как-нибудь гарантировать, что каждой строке будет присвоен уникальный цвет, используя matplotlib и более 20 строк?

спасибо

Ответы [ 3 ]

94 голосов
/ 06 декабря 2011

Ответ на ваш вопрос связан с двумя другими вопросами SO.

Ответ на Как выбрать новый цвет для каждой построенной линии на рисунке в matplotlib? объясняет, какопределить список цветов по умолчанию, который циклически проходит, чтобы выбрать следующий цвет для построения.Это делается с помощью метода Axes.set_color_cycle .

Однако вы хотите получить правильный список цветов, и это проще всего сделать с помощью карты цветов, как объясняется в ответе на этот вопрос: Создать генератор цветов из заданной карты цветов в matplotlib.Там цветовая карта принимает значение от 0 до 1 и возвращает цвет.

Итак, для ваших 20 строк вы хотите переключаться с 0 на 1 с шагом 1/20.В частности, вы хотите циклически изменить форму от 0 до 19/20, потому что 1 отображается обратно в 0.

Это сделано в этом примере:

import matplotlib.pyplot as plt
import numpy as np

NUM_COLORS = 20

cm = plt.get_cmap('gist_rainbow')
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_color_cycle([cm(1.*i/NUM_COLORS) for i in range(NUM_COLORS)])
for i in range(NUM_COLORS):
    ax.plot(np.arange(10)*(i+1))

fig.savefig('moreColors.png')
plt.show()

Это результирующий показатель:

Yosemitebear Mountain Giant Double Rainbow 1-8-10

Альтернативное, лучшее (дискуссионное) решение

Существует альтернативный способ использования объекта ScalarMappable для преобразования диапазона значений вцвета.Преимущество этого метода заключается в том, что вы можете использовать нелинейный Normalization для преобразования из индекса строки в фактический цвет.Следующий код дает тот же точный результат:

import matplotlib.pyplot as plt
import matplotlib.cm as mplcm
import matplotlib.colors as colors
import numpy as np

NUM_COLORS = 20

cm = plt.get_cmap('gist_rainbow')
cNorm  = colors.Normalize(vmin=0, vmax=NUM_COLORS-1)
scalarMap = mplcm.ScalarMappable(norm=cNorm, cmap=cm)
fig = plt.figure()
ax = fig.add_subplot(111)
# old way:
#ax.set_color_cycle([cm(1.*i/NUM_COLORS) for i in range(NUM_COLORS)])
# new way:
ax.set_color_cycle([scalarMap.to_rgba(i) for i in range(NUM_COLORS)])
for i in range(NUM_COLORS):
    ax.plot(np.arange(10)*(i+1))

fig.savefig('moreColors.png')
plt.show()

Примечание об устаревании
В более поздних версиях mplib (1.5+) функция set_color_cycle былаустарел в пользу ax.set_prop_cycle(color=[...]).

16 голосов
/ 06 июля 2017

У меня был сюжет с 12 линиями, и мне было трудно различать линии с похожими цветами, когда я попробовал метод Янна .Мои линии также появлялись парами, поэтому я использовал один и тот же цвет для двух линий в каждой паре и использовал две разные ширины линии.Вы также можете изменить стиль линии, чтобы получить больше комбинаций.

Вы можете использовать set_prop_cycle(), но я просто изменил объекты линии после вызова plot().

Вот пример Янна с тремя различными значениями ширины линии:

import matplotlib.pyplot as plt
import numpy as np

NUM_COLORS = 20

cm = plt.get_cmap('gist_rainbow')
fig = plt.figure()
ax = fig.add_subplot(111)
for i in range(NUM_COLORS):
    lines = ax.plot(np.arange(10)*(i+1))
    lines[0].set_color(cm(i//3*3.0/NUM_COLORS))
    lines[0].set_linewidth(i%3 + 1)

fig.savefig('moreColors.png')
plt.show()

Example plot with line widths

Вот тот же пример с различными стилями линий.Конечно, вы можете объединить их, если хотите.

import matplotlib.pyplot as plt
import numpy as np

NUM_COLORS = 20
LINE_STYLES = ['solid', 'dashed', 'dashdot', 'dotted']
NUM_STYLES = len(LINE_STYLES)

cm = plt.get_cmap('gist_rainbow')
fig = plt.figure()
ax = fig.add_subplot(111)
for i in range(NUM_COLORS):
    lines = ax.plot(np.arange(10)*(i+1))
    lines[0].set_color(cm(i//NUM_STYLES*float(NUM_STYLES)/NUM_COLORS))
    lines[0].set_linestyle(LINE_STYLES[i%NUM_STYLES])

fig.savefig('moreColors.png')
plt.show()

Example plot with line styles

8 голосов
/ 17 января 2018

Чтобы построить из ответа Дона Киркби , если вы хотите установить / использовать seaborn , тогда вы можете рассчитать цвета для вас:

import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

NUM_COLORS = 20
LINE_STYLES = ['solid', 'dashed', 'dashdot', 'dotted']
NUM_STYLES = len(LINE_STYLES)

sns.reset_orig()  # get default matplotlib styles back
clrs = sns.color_palette('husl', n_colors=NUM_COLORS)  # a list of RGB tuples
fig, ax = plt.subplots(1)
for i in range(NUM_COLORS):
    lines = ax.plot(np.arange(10)*(i+1))
    lines[0].set_color(clrs[i])
    lines[0].set_linestyle(LINE_STYLES[i%NUM_STYLES])

fig.savefig('moreColors.png')
plt.show()

Помимо возможности использовать различные цветовые палитры Seaborn, вы можете получить список кортежей RGB , который можно использовать / манипулировать позже, если это будет необходимо.Очевидно, что вы можете вычислить что-то подобное, используя цветовые карты matplotlib, но я считаю, что это удобно.seaborn husl color map with 20 colors

...