#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})