#colors #seaborn
#Цвет #seaborn
Вопрос:
У меня есть фрейм данных, где в столбце Products есть много разных элементов, давайте покажем только некоторые:
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
data = np.array([[1, 1, 570], [2, 1, 650], [1, 2, 27], [2, 2, 64], [1, 3, 125], [2, 3, 216],
[1, 'item_1', 343], [2, 'item_1', 340], [1, 'item_2', 343], [2, 'item_2', 345]])
df = pd.DataFrame(data=data, columns=["Flag", "Products", "Value"])
Я использую Seaborn для получения следующего lineplot:
sns.set_theme()
sns.set_style("ticks")
sns.set_context("paper")
fig1, ax1 = plt.subplots()
sns.lineplot(data=df, x="Flag", y="Value",
hue="Products", style="Products", ax=ax1)
plt.legend(bbox_to_anchor=(1.02, 1),borderaxespad=0)
fig1.tight_layout()
Таким образом, все строки имеют стиль, «выбранный» Seaborn, но мне нужно установить определенный цвет и стиль линии (не пунктирный) для продуктов с именами ‘item_1’ и ‘item_2’.
До сих пор я нашел следующее решение:
palette = {c:'red' if c=='item_1' else 'blue' for c in df.Products.unique()}
sns.lineplot(data=df, x="Flag", y="Value",
hue="Products", style="Products", palette=palette, ax=ax1)
Итак, я могу установить красный цвет только для item_1, но все остальные строки синие, хотя я хотел бы:
- установите красный цвет и не пунктирные линии как для items_1, так и для items_2
- установите другую цветовую палитру (например, яркую) для всех остальных линий
Возможно ли это сделать?
Ответ №1:
palette=
и dashes=
может быть передан словарь, отображающий уровни столбца, используемые для разных цветов / стилей.
Вы можете сгенерировать эти словари вручную или программно (в зависимости от того, сколько уровней у вас есть).
например, цветовая палитра:
#color palette
cmap = sns.color_palette("bright")
palette = {key:value for key,value in zip(data[hue_col].unique(), cmap)}
palette['item_1'] = 'red'
palette['item_2'] = 'red'
вывод:
{'1': (0.00784313725490196, 0.24313725490196078, 1.0), '2': (1.0, 0.48627450980392156, 0.0), '3': (0.10196078431372549, 0.788235294117647, 0.2196078431372549), 'item_1': 'red, 'item_2': 'red'}
мы присваиваем каждому уровню цвет, отличный от цвета палитры «bright», и при необходимости мы можем исправить некоторые значения вручную (хотя имейте в виду, что в палитре bright уже есть цвет, очень похожий на красный, поэтому может возникнуть некоторая путаница).
То же самое можно сделать для стиля штриха:
#style palette
dash_list = sns._core.unique_dashes(data[style_col].unique().size 1)
style = {key:value for key,value in zip(data[style_col].unique(), dash_list[1:])}
style['item_1'] = '' # empty string means solid
style['item_2'] = ''
вывод:
{'1': (4, 1.5), '2': (1, 1), '3': (3, 1.25, 1.5, 1.25), 'item_1': '', 'item_2': ''}
Здесь я использую одну из частных функций seaborn (используйте на свой страх и риск, может измениться в любое время), чтобы сгенерировать список стилей штрихов, а затем вручную установить конкретные уровни, которые я хочу, чтобы иметь сплошную линию. Я запрашиваю слишком много элементов в dash_list
, потому что первый элемент всегда представляет собой сплошную линию, и я хочу зарезервировать сплошные линии для item_1
и item_2
.
полный код:
data = df
x_col = 'Flag'
y_col = "Value"
hue_col = "Products"
style_col = "Products"
#color palette
cmap = sns.color_palette("bright")
palette = {key:value for key,value in zip(data[hue_col].unique(), cmap)}
palette['item_1'] = 'red'
palette['item_2'] = 'red'
#style palette
dash_list = sns._core.unique_dashes(data[style_col].unique().size 1)
style = {key:value for key,value in zip(data[style_col].unique(), dash_list[1:])}
style['item_1'] = '' # empty string means solid
style['item_2'] = ''
sns.set_theme()
sns.set_style("ticks")
sns.set_context("paper")
fig1, ax1 = plt.subplots()
sns.lineplot(data=df, x=x_col, y=y_col,
hue=hue_col, palette=palette,
style=style_col, dashes=style,
ax=ax1)
plt.legend(bbox_to_anchor=(1.02, 1),borderaxespad=0)
fig1.tight_layout()
Комментарии:
1. Большое спасибо @Diziet Asahi, действительно, это работает в примере dataframe! Но в моем полном фрейме данных, который содержит еще много элементов, я получаю сообщение об ошибке: в словаре палитры отсутствуют ключи: {‘9′, ’20’, …}. Итак, как я могу справиться с этой ошибкой? Учтите, что мне нужно анализировать фреймы данных, в которых количество элементов различно. Кроме того, есть ли способ установить linestyle для всех элементов с именем ‘item_x’ вместо ввода каждого из них?
Ответ №2:
Большое спасибо @Diziet Asahi, действительно, это работает в примере dataframe! Но в моем полном фрейме данных, который содержит еще много элементов, я получаю сообщение об ошибке:
В словаре палитры отсутствуют ключи: {‘9′, ’20’, …}
Я предполагаю, что это связано с тем, что цветовая палитра по умолчанию в seaborn — это качественная палитра, состоящая только из десяти различных оттенков. Чтобы справиться с этой ошибкой, я установил следующую цветовую палитру:
cmap = sns.color_palette("hls", 75)
Это работает также при выборе цветового пространства «husl».