2025, Oct 02 07:17
Как скрыть лишние подписи в легенде Seaborn/Matplotlib без хаков
Как убрать лишние подписи в легенде Seaborn/Matplotlib в новых версиях matplotlib. Получаем handles/labels, фильтруем нужные и передаем их назад в legend.
Когда на графике Seaborn одновременно несколько линий и полосы погрешностей, легенда быстро захламляется. Раньше часто использовали хитрость — передавали в вызов legend библиотеки matplotlib символы нижнего подчёркивания, чтобы скрыть лишние элементы. В новых версиях matplotlib (>3.10) это поведение убрали, из‑за чего старый подход перестал работать и в легенде остаются подписи, которые вы не хотите показывать.
Минимальный пример проблемы
Ниже фрагмент кода строит многострочный график Seaborn и пробует спрятать некоторые элементы легенды с помощью нижних подчёркиваний. Раньше это подавляло подписи, но в актуальном matplotlib больше не работает.
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
data_tbl = pd.DataFrame({'timepoint': np.random.randint(0, 10, 1000),
      'class': np.random.choice(['cat', 'dog', 'duck', 'hare'], 1000),
      'probability': np.random.rand(1000)
})
sns.lineplot(data_tbl, x='timepoint', y='probability', hue='class')
# раньше подстановка нижних подчёркиваний вместо имён скрывала подпись
plt.legend(['cat', *['_']*5, 'hare'])
Что происходит
Этот трюк с подчёркиваниями опирался на устаревшее поведение, которого больше нет. В случае с Seaborn вы также не управляете напрямую вызовами построения matplotlib, поэтому не можете на лету назначать подписи. Главное — работать с тем, что уже создал Seaborn: объектами легенды (handles) и подписями, прикреплёнными к осям. Если выбрать только нужные элементы и передать их обратно в legend, получится аккуратная, избирательная легенда без опоры на снятую функциональность.
Решение: отфильтровать элементы легенды, созданные Seaborn
Сохраните результат вызова lineplot в переменную, извлеките сгенерированные объекты и подписи, оставьте только те, что должны быть видны, и передайте отфильтрованный набор обратно в legend. Такой подход делает код явным и совместимым с текущими версиями matplotlib.
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
data_tbl = pd.DataFrame({'timepoint': np.random.randint(0, 10, 1000),
      'class': np.random.choice(['cat', 'dog', 'duck', 'hare'], 1000),
      'probability': np.random.rand(1000)
})
axis_obj = sns.lineplot(data_tbl, x='timepoint', y='probability', hue='class')
# получите все объекты/подписи, созданные seaborn
all_handles, all_labels = axis_obj.get_legend_handles_labels()
# выберите, какие оставить
show_only = ["cat", "hare"]
filtered_handles = [hh for hh, ll in zip(all_handles, all_labels) if ll in show_only]
filtered_labels  = [ll for ll in all_labels if ll in show_only]
axis_obj.legend(filtered_handles, filtered_labels)
plt.show()
Почему это важно
Понятная легенда — важная часть читаемости графика, особенно когда показываете несколько категорий и полосы неопределённости. Опора на удалённое поведение хрупка; явная фильтрация элементов легенды делает намерение прозрачным и сохраняет одинаковый вид графиков между версиями. Такой приём хорошо сочетается и с более высокоуровневым API Seaborn, где сами вызовы построения не под вашим прямым контролем.
Выводы
Откажитесь от старого трюка с подчёркиваниями. Считайте легенду этапом постобработки: получите оси от Seaborn, извлеките объекты и подписи и верните в legend только те элементы, которые должен видеть пользователь. Эта небольшая правка делает конвейер визуализации чище, предсказуемее и устойчивее к будущим изменениям.