Изменение стиля маркера в Matplotlib 2D точечная диаграмма с цветовой полосой в соответствии с данными кластера

#python #matplotlib #plot #cluster-analysis #scatter-plot

#python #matplotlib #график #кластерный анализ #точечная диаграмма

Вопрос:

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

Фиктивный набор данных :

 x = [48.959 49.758 49.887 50.593 50.683 ]
y = [122.310 121.29 120.525 120.252 119.509]
z = [136.993 133.128 143.710 129.088 139.860]
  

Я строю x, y и использую z в качестве цветовой оси, используя следующий код

 plt.scatter(
x=x, y=y, c=z, label="CO2 Emissions Saved Cumulative", cmap=cm1)
  

Вот как это выглядит для всех данных

Теперь я выполнил кластеризацию K средних в своем наборе данных и нашел три кластера. Например

 [0 0 0 0 0 2 1 2 1 2 1 1 2 1 1 1 2 2 2 2 2]
  

Я нашел следующее решение для их построения, дифференцируя стиль маркера

 ax.scatter(x[cluster == 0], y[cluster == 0], marker="*")
ax.scatter(x[cluster == 1], y[cluster == 1], marker="^")
ax.scatter(x[cluster == 2], y[cluster == 2], marker="s")
  

теперь проблема заключается в том, что при использовании этого метода он перезаписывает ось цвета, как показано в этом примере изображения
пример кластерного графика

Как я могу избежать этого, чтобы не изменять цветовую ось маркеров и по-прежнему использовать значения z по умолчанию для цветовой оси. Я хочу, чтобы график изменял стиль маркера только в соответствии с данными кластера. и не изменять цвет на основе данных кластера. Спасибо

Ответ №1:

Вам необходимо масштабировать z-значение каждого кластера до одного и того же масштаба, чтобы у вас была единая цветовая полоса для 3 точечных графиков. Для этого вы можете использовать Normalize объект и передать эту нормализацию в scatter using norm= .

 x = np.array([48.959, 49.758, 49.887, 50.593, 50.683 ])
y = np.array([122.310, 121.29, 120.525, 120.252, 119.509])
z = np.array([136.993, 133.128, 143.710, 129.088, 139.860])
cluster = np.array([0, 1, 0, 2, 2])

mini, maxi = np.min(z), np.max(z)
norm = plt.Normalize(mini, maxi)
fig, ax = plt.subplots()
a = ax.scatter(x[cluster == 0], y[cluster == 0], marker="*", c=z[cluster == 0], norm=norm)
a = ax.scatter(x[cluster == 1], y[cluster == 1], marker="^", c=z[cluster == 1], norm=norm)
a = ax.scatter(x[cluster == 2], y[cluster == 2], marker="s", c=z[cluster == 2], norm=norm)
fig.colorbar(a)
  

введите описание изображения здесь

Комментарии:

1. Спасибо за ваш ответ @Diziet. Тем не менее, я хочу сохранить тот же масштаб, что и на первом прикрепленном изображении. Единственное изменение, которое я хочу добавить к нему, — это иметь стиль маркера, основанный на кластере. в предложенном вами решении отображается диапазон цветовой полосы только от 0-1

2. а также, зачем нормализовать значения z? кластеризация была выполнена для всего набора данных (x, y, z)

3. Я добиваюсь того же, просто добавляя c = z[cluster == 0] . Результаты этого и вашего решения аналогичны. Это не то, чего я хотел.

4. Цель состоит в том, чтобы масштабировать z-значение каждого кластера до одного и того же масштаба, чтобы у вас была единая цветовая полоса для 3 точечных графиков. Я включил полный код

5. потрясающе, понял. именно то, что я хотел. Спасибо.

Ответ №2:

Менее подробным и более надежным решением для больших наборов данных является использование библиотеки pandas and seaborn :

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

x = [48.959, 49.758, 49.887, 50.593, 50.683 ]
y = [122.310, 121.29, 120.525, 120.252, 119.509]
z = [136.993, 133.128, 143.710, 129.088, 139.860]
kmean = np.array([0, 1, 0, 2, 2])

df = pd.DataFrame({'x':x,'y':y,'z':z, 'km_z':kmean})
sns.scatterplot(data = df, x='x', y='y', hue='km_z', style='km_z')
  

который выдает следующий результат

введите описание изображения здесь

Кроме того, вы можете использовать pandas.cut функцию для построения ячеек (это то, что мне регулярно нужно для создания графиков, где я могу использовать третье непрерывное значение в качестве параметра). Способ его использования :

 import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
x = [48.959, 49.758, 49.887, 50.593, 50.683 ]
y = [122.310, 121.29, 120.525, 120.252, 119.509]
z = [136.993, 133.128, 143.710, 129.088, 139.860]

df = pd.DataFrame({'x':x,'y':y,'z':z})
df['bins'] = pd.cut(df.z, bins=3)
sns.scatterplot(data = df, x='x', y='y', hue='bins', style='bins')
  

и это приводит к следующему примеру:

введите описание изображения здесь


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

введите описание изображения здесь