Диаграмма рассеяния Python: как использовать цветовую карту, которая имеет те же цвета, что и цветовой цикл
Я пытаюсь раскрасить кластеры в точечной диаграмме, и мне удалось двумя разными методами.
В первом я итеративно строю график каждого кластера, во втором я рисую все данные сразу и окрашиваю кластеры в соответствии с их метками [0, 1, 2, 3,4].
Я доволен результатом, который я получаю example1
а также example3
но я не понимаю, почему раскраска так резко меняется при раскраске кластеров в соответствии с метками, а не при итеративном построении каждого кластера.
Кроме того, почему второй кластер (несмотря на наличие всегда метки "1") имеет разный цвет в example1 и example3?
import matplotlib.pyplot as plt
plt.style.use('fivethirtyeight') #irrelevant here, but coherent with the examples=)
fig, ax = plt.subplots(figsize=(6,4))
for clust in range(kmeans.n_clusters):
ax.scatter(X[kmeans.labels_==clust],Y[kmeans.labels_==clust])
ax.set_title("example1")`
а также
plt.figure(figsize = (6, 4))
plt.scatter(X,Y,c=kmeans.labels_.astype(float))
plt.title("example2")
(Я знаю, что могу явно определить цветовую карту для второго метода, но я не смог найти ни одной, которая воспроизводит результаты в примере 1)
Вот минимальный рабочий пример
import matplotlib.pyplot as plt
import pandas as pd
plt.style.use('fivethirtyeight') #irrelevant here, but coherent with the examples=)
X=pd.Series([1, 2, 3, 4, 5, 11, 12, 13, 14, 15])
Y=pd.Series([1,1,1,1,1,2,2,2,2,2])
clusters=pd.Series([0,0,0,0,0,1,1,1,1,1])
fig, ax = plt.subplots(figsize=(6,4))
for clust in range(2):
ax.scatter(X[clusters==clust],Y[clusters==clust])
ax.set_title("example3")
plt.figure(figsize = (6, 4))
plt.scatter(X,Y, c=clusters)
plt.title("example4")
1 ответ
Когда вы перебираете кластеры и строите scatter
без указания какого-либо цвета будут использоваться цвета по умолчанию активного свойства cycler (цветовой цикл). Активное свойство cycler определено в rcParams
, Он устанавливается через используемый стиль; в вашем случае, используя 'fivethirtyeight'
print(plt.rcParams["axes.prop_cycle"])
> cycler('color', ['#008fd5', '#fc4f30', '#e5ae38', '#6d904f', '#8b8b8b', '#810f7c'])
Первые два цвета этого ('#008fd5', '#fc4f30') - это то, что вы видите на графике.
Когда вы используете scatter
с clusters
в качестве аргумента цвета эти значения будут сопоставлены с цветом с помощью карты цветов. Если цветовая карта не указана, будет использоваться цветовая карта по умолчанию, определенная в rcParam
,
print(plt.rcParams["image.cmap"])
> "viridis"
'fivethirtyeight'
Стиль не определяет никакой специальной карты цветов, поэтому значение по умолчанию не изменится. (Тот факт, что на вашей картинке вы видите цветную карту, отличную от viridis, объясняется тем, что был еще какой-то еще активный код, который не показан в вопросе.)
На этом этапе мне нужно начать перевод; Я думаю, что ваш вопрос на самом деле заключается в том, как заставить единый разброс использовать цветовую карту, которая имеет те же цвета, что и цветовой цикл. Ни одна из предопределенных цветовых карт не содержит цветов тридцатитысячного цикла. Следовательно, вы должны определить эту цветовую карту вручную, взяв цвета из цикла,
import matplotlib.colors as mcolors
cmap = mcolors.ListedColormap(plt.rcParams['axes.prop_cycle'].by_key()['color'])
Теперь вам нужен способ индексировать цветовую карту, потому что у вас есть отдельные кластеры.
n = len(clusters.unique())
norm = mcolors.BoundaryNorm(np.arange(n+1)-0.5, n)
Конечно, для этого необходимо, чтобы количество цветов в цветовой карте было больше или равно количеству классов - как в данном случае.
Собираем все вместе (я добавил еще одну категорию, чтобы сделать ее более наглядной)
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.colors as mcolors
plt.style.use('fivethirtyeight') #relevant here!!
X=pd.Series([1, 2, 3, 4, 5, 11, 12, 13, 14, 15])
Y=pd.Series([1,1,1,1,1,2,2,2,2,2])
clusters=pd.Series([0,0,0,0,0,1,1,1,1,2])
cmap = mcolors.ListedColormap(plt.rcParams['axes.prop_cycle'].by_key()['color'])
n = len(clusters.unique())
norm = mcolors.BoundaryNorm(np.arange(n+1)-0.5, n)
plt.figure(figsize = (6, 4))
sc = plt.scatter(X,Y, c=clusters, cmap=cmap, norm=norm)
plt.colorbar(sc, ticks=clusters.unique())
plt.title("example4")
plt.show()