hue в Seaborn: цвет как третье измерение графика
hue разбивает график по третьей колонке таблицы: точки, столбцы и линии раскрашиваются по группам, а легенда строится сама. Разбираем scatterplot, barplot, lineplot и hue_order.
Редакция Питоники
Две колонки таблицы легко становятся осями X и Y: бюджет против продаж, площадь против цены. Но настоящие таблицы шире: у каждой строки есть ещё канал, город, категория — и сравнивать группы хочется на одном графике, а не на трёх отдельных. Для этого в Seaborn есть параметр hue=. hue добавляет третье измерение, раскрасив данные по значениям ещё одной колонки, — легенда и цвета появляются сами. Набор цветов при этом берётся из палитры, которую мы разбирали в прошлом уроке.
План урока: hue в scatterplot и lineplot, связь hue с группировкой pandas, hue_order для порядка групп, перенос легенды и две типовые ловушки — числовая колонка в hue и слишком много групп.
hue в scatterplot: три канала на одной картинке
Сквозной пример урока — рекламные каналы интернет-магазина. По каждой кампании известны бюджет и выручка; колонка channel делит их на поиск, соцсети и email:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
ads = pd.DataFrame({
"channel": ["поиск", "поиск", "соцсети", "соцсети", "email", "email",
"поиск", "соцсети", "email", "поиск", "соцсети", "email"],
"budget": [30, 45, 25, 40, 15, 22, 60, 55, 30, 50, 70, 18],
"sales": [310, 420, 260, 390, 140, 205, 505, 470, 290, 430, 590, 175],
})
sns.set_theme()
ax = sns.scatterplot(data=ads, x="budget", y="sales", hue="channel")
ax.set_title("Реклама: бюджет и выручка по каналам")
ax.set_xlabel("Бюджет, тыс. руб.")
ax.set_ylabel("Выручка, тыс. руб.")
plt.show()
График отображается под редактором
Один вызов — и три облака точек читаются раздельно: поиск и соцсети тянутся вдоль общей диагонали (больше бюджет — больше выручка), а email лежит заметно ниже при тех же бюджетах. Без hue три канала смешались бы в одно облако, и этот вывод пришлось бы добывать перебором фильтров.
Что hue делает под капотом: группировка
hue — это группировка pandas, нарисованная цветом: Seaborn разрезает таблицу по значениям колонки и рисует каждую часть своим слоем. Проверим числами то же самое через groupby из урока про группировку Pandas:
import pandas as pd
ads = pd.DataFrame({
"channel": ["поиск", "поиск", "соцсети", "соцсети", "email", "email",
"поиск", "соцсети", "email", "поиск", "соцсети", "email"],
"sales": [310, 420, 260, 390, 140, 205, 505, 470, 290, 430, 590, 175],
})
means = ads.groupby("channel")["sales"].mean().round(1)
print(means.tolist())
print(ads["channel"].nunique())
[202.5, 416.2, 427.5] 3
Три канала, и email отстаёт в среднем вдвое — ровно то, что показывает цвет на scatterplot. Разница в том, что groupby выдаёт одно число на группу, а hue сохраняет каждую точку: видны и средние, и разброс вокруг них, и выбросы.
hue в barplot и lineplot: один параметр везде
hue работает почти во всех функциях Seaborn и всегда означает одно и то же: «разбей по этому столбцу и раскрась». В barplot группы встают столбцами рядом — удобно сравнивать месяцы между городами:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
months = pd.DataFrame({
"month": ["Май", "Июнь", "Июль", "Август",
"Май", "Июнь", "Июль", "Август"],
"city": ["Москва", "Москва", "Москва", "Москва",
"Сочи", "Сочи", "Сочи", "Сочи"],
"revenue": [420, 510, 590, 480, 610, 780, 920, 860],
})
sns.set_theme()
ax = sns.barplot(data=months, x="month", y="revenue", hue="city")
ax.set_title("Выручка по месяцам: Москва против Сочи")
ax.set_ylabel("Выручка, тыс. руб.")
plt.show()
График отображается под редактором
В lineplot hue рисует по линии на каждую группу — классический способ сравнить два города или две модели на одной временной шкале:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
temps = pd.DataFrame({
"day": [1, 2, 3, 4, 5, 1, 2, 3, 4, 5],
"city": ["Сочи"] * 5 + ["Мурманск"] * 5,
"temp": [24, 25, 27, 26, 28, 12, 11, 14, 13, 15],
})
sns.set_theme()
ax = sns.lineplot(data=temps, x="day", y="temp", hue="city", marker="o")
ax.set_title("Дневная температура: две линии вместо двух графиков")
ax.set_xlabel("День наблюдений")
ax.set_ylabel("Температура, C")
plt.show()
График отображается под редактором
Линии идут почти параллельно: разница между городами держится около 12 градусов каждый день. Параллельность — признак постоянной разницы; если бы линии сближались или пересекались, это значило бы, что разрыв меняется во времени. В scatterplot и lineplot hue ещё и добавляет histplot разрез по распределениям — в четвёртом уроке мы уже видели, как два гистограммных слоя сравниваются по цвету.
hue_order: управляем порядком групп
По умолчанию Seaborn сортирует группы по значениям колонки — текстовые категории встают по алфавиту. Если нужен свой порядок (например, от меньшего тарифа к большему), его фиксирует hue_order=:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
orders = pd.DataFrame({
"day": ["Пн", "Пн", "Вт", "Вт", "Ср", "Ср", "Ср",
"Чт", "Чт", "Пт", "Пт", "Пт"],
"drink": ["латте", "капучино", "эспрессо", "латте", "капучино", "латте",
"эспрессо", "капучино", "латте", "эспрессо", "латте", "капучино"],
})
sns.set_theme()
ax = sns.countplot(
data=orders, x="day", hue="drink",
hue_order=["эспрессо", "капучино", "латте"],
)
ax.set_title("Напитки по дням: порядок в легенде задан hue_order")
plt.show()
График отображается под редактором
hue_order меняет и порядок столбцов внутри дня, и порядок строк легенды. Убедимся, что легенда запомнила заданный порядок — вытащим её подписи из объекта осей:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
orders = pd.DataFrame({
"day": ["Пн", "Пн", "Вт", "Вт", "Ср", "Ср", "Ср",
"Чт", "Чт", "Пт", "Пт", "Пт"],
"drink": ["латте", "капучино", "эспрессо", "латте", "капучино", "латте",
"эспрессо", "капучино", "латте", "эспрессо", "латте", "капучино"],
})
ax = sns.countplot(
data=orders, x="day", hue="drink",
hue_order=["эспрессо", "капучино", "латте"],
)
print([t.get_text() for t in ax.get_legend().get_texts()])
['эспрессо', 'капучино', 'латте']
Порядок совпал с заданным: алфавит уступил месту бизнес-логике. Тот же параметр у обычного order= управляет категориями оси X — оба принимают список значений в нужной последовательности.
Чтение легенды и её перенос
Легенда при hue создаётся автоматически: заголовком становится имя колонки, подписями — её значения. Читатель сопоставляет цвет с группой по легенде, поэтому её стоит ставить так, чтобы она не накрывала данные. За перенос отвечает sns.move_legend():
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
ads = pd.DataFrame({
"channel": ["поиск", "поиск", "соцсети", "соцсети", "email", "email",
"поиск", "соцсети", "email", "поиск", "соцсети", "email"],
"budget": [30, 45, 25, 40, 15, 22, 60, 55, 30, 50, 70, 18],
"sales": [310, 420, 260, 390, 140, 205, 505, 470, 290, 430, 590, 175],
})
sns.set_theme()
ax = sns.scatterplot(data=ads, x="budget", y="sales", hue="channel")
sns.move_legend(ax, "upper left", title="Канал")
ax.set_title("Легенда переехала в свободный угол")
plt.show()
График отображается под редактором
Первый аргумент — объект осей, второй — позиция: upper left, lower right, center и другие. Аргумент title= переименовал заголовок легенды: имя колонки channel из данных редко читается как подпись, а «Канал» — читается. Тонкости легенд Matplotlib разобраны в шестом уроке про оформление, и они применимы к Seaborn один в один.
Что дальше
hue — самый ходовой параметр библиотеки после data=: он в одну строку превращает одиночный график в сравнение групп. Со следующего урока он станет регулярным гостем: boxplot использует его для пар ящиков, а violinplot — для split-скрипок, где две группы делят одну фигуру пополам.
hue добавляет третье измерение, раскрасив данные по значениям ещё одной колонки, — легенда и цвета появляются сами.
Сначала предскажи ответ в голове — это главный навык программиста.
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
df = pd.DataFrame({
"day": ["Пн", "Пн", "Вт", "Вт"],
"drink": ["чай", "кофе", "чай", "кофе"],
})
ax = sns.countplot(data=df, x="day", hue="drink")
print(len(ax.containers))
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
df = pd.DataFrame({
"day": ["Пн", "Пн", "Вт", "Вт"],
"drink": ["чай", "кофе", "чай", "кофе"],
})
ax = sns.countplot(data=df, x="day", hue="drink", hue_order=["кофе", "чай"])
print([t.get_text() for t in ax.get_legend().get_texts()])
import pandas as pd
df = pd.DataFrame({
"city": ["Москва", "Казань", "Москва", "Казань"],
"sales": [10, 20, 30, 40],
})
print(df.groupby("city")["sales"].sum().tolist())
1. Что делает параметр hue="city" в sns.lineplot?
2. Какой порядок групп hue выберет по умолчанию?
3. Почему hue="price" с числовой колонкой — плохая идея?
4. Что делает sns.move_legend(ax, "upper left")?
5. Чем связан hue с groupby из pandas?
В редакторе — кампании интернет-магазина: budget (бюджет, тыс. руб.) и sales (выручка, тыс. руб.). Постройте scatterplot с разбивкой hue="channel", палитрой colorblind и легендой в верхнем левом углу с заголовком «Канал».
Что такое hue в Seaborn простыми словами?
Это параметр, который раскрашивает график по значениям ещё одной колонки таблицы: каждая группа получает свой цвет, а легенда строится автоматически. sns.scatterplot(data=df, x="budget", y="sales", hue="channel") покажет все каналы на одной картинке — это третье измерение графика без единой строки группировки.
Урок 9: hue как третье измерениеКак задать свой порядок групп в легенде?
Параметром hue_order=: передайте список значений в нужной последовательности, и он применится и к цветам на графике, и к строкам легенды. Для категорий самой оси X аналогично работает order=. По умолчанию Seaborn сортирует группы по значениям колонки — текстовые по алфавиту.
Как переместить легенду на графике Seaborn?
sns.move_legend(ax, "upper left") — первым аргументом объект осей, вторым позиция (upper left, lower right, center и т.д.). Там же меняется заголовок: sns.move_legend(ax, "upper left", title="Канал"). Легенда при hue создаётся сама, поэтому обычно её только переносят.
Сколько групп выдерживает hue?
Комфортно — три-четыре: глаз удерживает столько оттенков одновременно. При большем числе столбцы сужаются, легенда разрастается, а цвета повторяются. Сводите категории до осмысленных групп через pd.cut() или переходите к малым кратным — сетке графиков FacetGrid, по панели на группу.
Понравился урок? Сошлитесь на него
«hue добавляет третье измерение, раскрасив данные по значениям ещё одной колонки, — легенда и цвета появляются сами.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что читать дальше
Seaborn · Урок 8
Палитры цветов в Seaborn: как подобрать цвета под задачу
Три типа палитр Seaborn, функция sns.color_palette(), безопасный набор colorblind и своя палитра из фирменных цветов — одна строка palette= на каждый случай.
Seaborn · Урок 10
boxplot в Seaborn: как читать ящик с усами и сравнивать группы
Один символ — и вся форма распределения перед глазами: медиана, квартили, разброс и выбросы. Учимся читать ящик с усами, сравнивать группы и добавлять hue.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
Matplotlib / Seaborn · Урок 2
Линейные графики в Matplotlib: plot, цвета, стили и подписи
plt.plot() под микроскопом: цвета, маркеры, стили линий, легенды, диапазоны осей и кейс с двумя температурными кривыми за месяц.
линейный график pythonкак построить линейный график в python
Matplotlib / Seaborn · Урок 4
Диаграммы рассеяния scatter: ищем связи между величинами
scatter для поиска связей между величинами: форма облака точек, цвет и размер как третье измерение, alpha против оверплоттинга и кейс с 300 измерениями.
корреляция на графикецвет точек matplotlib
Seaborn · Урок 5
scatterplot в Seaborn: связь двух величин на точках
Диаграмма рассеяния показывает связь двух числовых столбцов: одна строка таблицы — одна точка. Управляем размером s и прозрачностью alpha и учимся видеть кластеры.
seaborn scatterplotsns scatterplot