Регплот Сиборна: легенда о слиянии точек и линий

#python #matplotlib #seaborn

Вопрос:

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

 fig, ax = plt.subplots()
legends = []
for group in groups:
    some_group_plot = sns.regplot(x='x', y='y', data=pd.DataFrame({'x': x_array,
                                                                   'y': y_array}),
                                  ci=None, color=next(palette),
                                  ax=ax,
                                  line_kws={'lw': 2},
                                  scatter=True, truncate=False)
    legends.append(group)
plt.legend(legends, fontsize=18)

 

Ответ №1:

Некоторые замечания:

  • Сиборн полагается на matplotlib для легенды. В matplotlib легенды создаются с помощью label= параметра во многих его функциях. Также sns.regplot принимает этот параметр.
  • sns.regplot возвращает тот ax , на котором он создал сюжет. При ax= использовании параметра переменная some_group_plot будет точно такой же, как и заданная ax , и ее можно опустить.

Вот несколько примеров кода, включая необходимый импорт библиотеки и некоторые случайные данные:

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

np.random.seed(123)
fig, ax = plt.subplots()
groups = ['group 1', 'group 2', 'group 3']
for group in groups:
    sns.regplot(x='x', y='y', data=pd.DataFrame({'x': np.random.rand(5), 'y': np.random.rand(5)}),
                ci=None,
                ax=ax,
                line_kws={'lw': 2},
                scatter=True, truncate=False, label=group)
plt.legend(fontsize=10)
plt.show()
 

регплоты сиборна с легендой

Если вам также нужна метка для линии регрессии, вы можете добавить label ключевое слово в line_kws :

 for group in groups:
    sns.regplot(x='x', y='y', data=pd.DataFrame({'x': np.random.rand(5), 'y': np.random.rand(5)}),
                ci=None,
                ax=ax,
                line_kws={'lw': 2, 'label': 'Regression for '   group},
                scatter=True, truncate=False, label=group)
plt.legend(fontsize=10, ncol=2)
 

Чтобы объединить оба маркера, новейшие версии matplotlib (протестированы с 3.4.2) позволяют объединять маркеры в кортежи и по умолчанию накладывать их друг на друга. Вы можете использовать ax.get_legend_handles_labels() , чтобы извлечь существующие дескрипторы для легенды и объединить их.

 np.random.seed(123)
fig, ax = plt.subplots()
groups = ['group 1', 'group 2', 'group 3']
for group in groups:
    sns.regplot(x='x', y='y', data=pd.DataFrame({'x': np.random.rand(5), 'y': np.random.rand(5)}),
                ci=None,
                ax=ax,
                line_kws={'lw': 2, 'label': 'Regression for '   group},
                scatter=True, truncate=False, label=group)
handles, labels = ax.get_legend_handles_labels()
n = len(groups)
plt.legend(handles=[(h1, h2) for h1, h2 in zip(handles[:n], handles[n:])],
           labels=labels[n:],
           fontsize=10)
plt.show()
 

условные обозначения с комбинированными маркерами

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

1. Безусловно, большое вам спасибо! У меня есть продолжение: маркеры легенды немного смещены от центра, что не является проблемой для круглых маркеров, но будет маскировать другие, есть ли способ правильно выровнять их по линиям? Я также могу заметить, что линия расположена перед маркером, который я также хотел бы исправить, если это можно сделать.

2. Для центрирования маркеров в легенде можно использовать дополнительный параметр plt.legend(..., scatteryoffsets=[0.5]) (по умолчанию используется 0.375 только одна точка). Чтобы изменить z-порядок, вы можете использовать for h1 in handles[:n]: h1.set_zorder(1) . В качестве альтернативы, если вы также хотите изменить z-порядок основного сюжета, вы можете добавить sns.regplot(..., scatter_kws={'zorder':3})