Как я могу объединить группы оттенков и стилей в легенде о Морборне?

#python #matplotlib #seaborn

Вопрос:

Я делаю линейный график Seaborn для продольных данных, которые сгруппированы по «Подшкале» hue и по «Элементу» style .

Вот мой код (надеюсь, это понятно и без данных):

 ax = sns.lineplot(data = df, x = 'Week', y = 'Value', style = 'Item', hue = 'Subscale', palette = 'colorblind', markers = True)
plt.legend(bbox_to_anchor = (1.03, 1.02), fontsize = 10)
 

Откуда у меня этот сюжет:
введите описание изображения здесь

Я хочу объединить подзаголовки так, чтобы в них отображалась только легенда для «Элемента», но элементы окрашены в соответствии с «Подшкалой», примерно так: введите описание изображения здесь

Мне не удалось создать это, так что, если кто-нибудь из вас может помочь, я был бы очень признателен! Спасибо 🙂

Ответ №1:

Если я правильно понимаю, все элементы определенного типа имеют одинаковую нижнюю шкалу. Таким образом, у вас уже есть (или вы можете создать) словарь, который сопоставляет тип элемента с соответствующей подшкалой.

Сиборн создает следующие метки для легенды:

  • «Подшкала» для подзаголовка
  • каждая из подшкал
  • «Товар» для второго подзаголовка
  • каждый из пунктов

Каждая метка соответствует «маркеру», определяющему, как выглядит маркер.

Следующий код:

  • находит индекс 'Item' , чтобы иметь возможность разделять массивы меток и дескрипторов
  • извлекает цвета из «подшкалы»
  • применяет эти цвета к маркерам элементов
  • использует только элементы для легенды
 import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np

# first create some random data similar to the description
np.random.seed(123)
items = ['01', '04', '05', '06', '07', '10', '11', '13']
N = len(items)
subscale_dict = {'01': 'A', '04': 'C', '05': 'C', '06': 'C', '07': 'A', '10': 'B', '11': 'B', '13': 'A'}

df = pd.DataFrame({'Week': np.tile(np.arange(7), N),
                   'Value': np.random.rand(7 * N),
                   'Item': np.repeat(items, 7)})
df['Subscale'] = df['Item'].apply(lambda i: subscale_dict[i])
df['Subscale'] = pd.Categorical(df['Subscale'])  # creates a fixed order

# create the line plot as before
ax = sns.lineplot(data=df, x='Week', y='Value', style='Item', hue='Subscale', palette='colorblind', markers=True)

# create a dictionary mapping the subscales to their color
handles, labels = ax.get_legend_handles_labels()
index_item_title = labels.index('Item')
color_dict = {label: handle.get_color()
              for handle, label in zip(handles[1:index_item_title], labels[1:index_item_title])}

# loop through the items, assign color via the subscale of the item idem
for handle, label in zip(handles[index_item_title   1:], labels[index_item_title   1:]):
    handle.set_color(color_dict[subscale_dict[ label]])

# create a legend only using the items
ax.legend(handles[index_item_title   1:], labels[index_item_title   1:], title='Item',
          bbox_to_anchor=(1.03, 1.02), fontsize=10)

plt.tight_layout()
plt.show()
 

sns.линейный график с пользовательской легендой

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

1. Ваше решение отлично работает, спасибо! Хотя много строк кода, подумал, что это может быть проще…