Перейти к содержанию

252 уроков, 17 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 8 из 20 Средний 25 мин 120 XP

Палитры цветов в Seaborn: как подобрать цвета под задачу

Три типа палитр Seaborn, функция sns.color_palette(), безопасный набор colorblind и своя палитра из фирменных цветов — одна строка palette= на каждый случай.

Редакция Питоники

Цвет — самый громкий канал на графике: глаз цепляется за него раньше, чем за подписи и числа. В седьмом уроке про темы мы настроили фон, сетку и шрифты; остался последний слой оформления — палитра. Seaborn собрал десятки готовых наборов цветов и простые правила их выбора: одна строка palette= отделяет аккуратный отчёт от пёстрого наброска.

В этом уроке разберёмся, какие бывают палитры, как посмотреть их цвета через sns.color_palette(), какой набор выбрать для категорий, а какой — для величин с порядком, и почему параметр palette="colorblind" стоит запомнить с первого дня работы с библиотекой.

Три типа палитр: категории, порядок, отклонение

Вся система палитр Seaborn держится на одном вопросе: что означает цвет на вашем графике? Ответов три, и под каждый построен свой тип наборов.

Тип палитрыЧто кодирует цветПримеры
Категориальная (qualitative)«Какой это тип»: жанры, города, каналыdeep, Set2, colorblind
Последовательная (sequential)«Сколько»: от малого к большомуBlues, YlGnBu, viridis
Дивергентная (diverging)«В какую сторону от середины»: прибыль и убытокRdBu_r, coolwarm, PiYG

Категории отвечают на вопрос «какой», последовательные — «сколько», дивергентные — «в какую сторону от середины». Перепутать их — значит вложить в цвет смысл, которого в данных нет: последовательная палитра на списке жанров намекнёт читателю, что «фантастика больше романа», хотя сравнивать жанры на шкале нельзя.

sns.color_palette(): посмотреть цвета до графика

Функция sns.color_palette() возвращает палитру как список кортежей RGB — три числа от 0 до 1 на каждый цвет. Это самый быстрый способ осмотреть набор: сколько в нём цветов и какие они.

Заглядываем внутрь палитры Set2
import seaborn as sns

palette = sns.color_palette("Set2")
print(len(palette))
print([round(c, 2) for c in palette[0]])
Вывод
8
[0.4, 0.76, 0.65]

Восемь цветов, и первый — приглушённый зелёный с координатами (0.4, 0.76, 0.65). Числа — доли красного, зелёного и синего канала: (1, 0, 0) — чистый красный, (0, 0, 0) — чёрный. Те же кортежи подходят любому методу Matplotlib в параметре color= — палитры Seaborn и цвета Matplotlib говорят на одном языке.

Категориальные палитры: цвета как ярлыки

Категориальные наборы собраны из заметно различающихся оттенков: deep (палитра по умолчанию), muted, pastel, bright, dark, colorblind и тематические наборы ColorBrewer вроде Set2. Применяются параметром palette= в любой функции построения графика:

Палитра Set2 на столбчатой диаграмме
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

books = pd.DataFrame({
    "genre": ["роман", "детектив", "фантастика", "детская",
              "нонфикшн", "роман", "детектив", "фантастика"],
    "sales": [42, 35, 28, 51, 19, 38, 31, 24],
})

sns.set_theme()
ax = sns.barplot(
    data=books, x="genre", y="sales",
    hue="genre", palette="Set2", legend=False,
)
ax.set_title("Продажи по жанрам: палитра Set2")
plt.show()
Вывод
График отображается под редактором
Первый запуск загружает pandas и seaborn — это займёт до минуты

Пара hue="genre", legend=False — типовой приём Seaborn 0.13: цвет по категории, но без дублирующей легенды, потому что имена жанров уже стоят по оси X. С версии 0.13 параметр palette= без hue= считается устаревшим — об этом отдельный питфолл ниже.

colorblind: палитра, которую видят все

Около 8% мужчин имеют нарушение цветовосприятия, и классическая пара красный-зелёный для них сливается в одно пятно. Палитра colorblind построена на наборе Okabe-Ito, который специально подобран различимым при дальтонизме, — тот же принцип мы упоминали в уроке про оформление Matplotlib. Сравните наборы рядом:

Палитра по умолчанию против colorblind
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

books = pd.DataFrame({
    "genre": ["роман", "детектив", "фантастика", "детская",
              "нонфикшн", "роман", "детектив", "фантастика"],
    "sales": [42, 35, 28, 51, 19, 38, 31, 24],
})

sns.set_theme()
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4), sharey=True)
sns.barplot(data=books, x="genre", y="sales", hue="genre",
            legend=False, ax=ax1)
sns.barplot(data=books, x="genre", y="sales", hue="genre",
            palette="colorblind", legend=False, ax=ax2)
ax1.set_title("Палитра по умолчанию (deep)")
ax2.set_title("Палитра colorblind")
plt.show()
Вывод
График отображается под редактором

Сравните второй цвет в каждой панели: в deep это красновато-оранжевый, в colorblind — отчётливо оранжевый, а красно-зелёных пар в наборе нет вовсе. Для отчёта, который уйдёт заказчику или в печать (где цвета искажаются ещё и на бумаге), colorblind — безопасный выбор по умолчанию. Включить его глобально можно вызовом sns.set_palette("colorblind"):

Глобальная смена палитры
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

orders = pd.DataFrame({
    "genre": ["роман", "детектив", "фантастика", "детская",
              "нонфикшн", "роман", "детектив", "фантастика"],
})

sns.set_theme()
sns.set_palette("colorblind")   # все графики ниже рисуются в colorblind
ax = sns.countplot(data=orders, x="genre", hue="genre", legend=False)
ax.set_title("Палитра включена глобально")
plt.show()
Вывод
График отображается под редактором

set_palette работает как set_theme из седьмого урока: меняет настройку сессии, и все последующие графики рисуются уже в ней. Удобно включить один раз в начале ноутбука и не думать о палитре дальше — параметр palette= останется для точечных исключений.

Последовательные палитры: когда величина имеет порядок

Если цвет кодирует количество — выручку, плотность, время — нужен набор, где оттенок плавно меняется от светлого к тёмному: Blues, Greens, YlGnBu, viridis. Посмотрим на крайние ступени градиента числом:

Градиент последовательной палитры
import seaborn as sns

blues = sns.color_palette("Blues", n_colors=5)
print([round(c, 2) for c in blues[0]])
print([round(c, 2) for c in blues[-1]])
Вывод
[0.84, 0.9, 0.96]
[0.06, 0.36, 0.64]

Первый цвет почти белый, последний — насыщенный синий: аргумент n_colors= задаёт число ступеней градиента. Тёмный оттенок считывается как «больше» мгновенно — на этом держатся тепловые карты, до которых доберёмся в уроке про heatmap. А пока применим градиент к столбцам вручную:

Светлый к тёмному: посещения по дням недели
import matplotlib.pyplot as plt
import seaborn as sns

days = ["Пн", "Вт", "Ср", "Чт", "Пт"]
visits = [120, 95, 88, 140, 205]
grad = sns.color_palette("Blues", n_colors=5)

sns.set_theme()
fig, ax = plt.subplots()
ax.bar(days, visits, color=grad)
ax.set_title("Посещения по дням: чем темнее, тем больше")
ax.set_ylabel("Посещения")
plt.show()
Вывод
График отображается под редактором

Здесь градиент честный: он упорядочен вместе со значениями visits — от спокойного понедельника к горячей пятнице. Порядок цветов совпал с порядком величин, и цвет работает на график, а не против него.

Дивергентные палитры: вокруг середины

Когда значения отклоняются от нормы — прибыль и убыток, отклонение температуры от среднего — нужна дивергентная палитра: два насыщенных края и бледная середина. Названия говорят сами за себя: RdBu_r (красный-синий), coolwarm, PiYG. Полная сила этих наборов раскроется в тепловых картах, а здесь — та же логика на столбцах прибыли:

Прибыль и убыток: минус красным, плюс синим
import matplotlib.pyplot as plt
import seaborn as sns

months = ["Март", "Апрель", "Май", "Июнь", "Июль"]
profit = [-12, 5, 18, -4, 25]
colors = ["#b2182b" if p < 0 else "#2166ac" for p in profit]

sns.set_theme()
fig, ax = plt.subplots()
ax.bar(months, profit, color=colors)
ax.axhline(0, color="black", linewidth=0.8)
ax.set_title("Прибыль по месяцам: дивергентная логика")
ax.set_ylabel("Тыс. руб.")
plt.show()
Вывод
График отображается под редактором

Нулевая линия делит график на две зоны, и цвет усиливает разделение: убытки красным, прибыль синим. Читатель понимает знак каждого столбца раньше, чем успевает посмотреть на ось Y, — именно эту скорость и покупают за дивергентную палитру.

Своя палитра: фирменные цвета

Палитрой может стать любой список цветов — hex-строками или RGB-кортежами. Фирменные цвета компании или единая гамма для дашборда — это один вызов:

Палитра из списка hex-цветов
import seaborn as sns

brand = sns.color_palette(["#2a9d8f", "#e9c46a", "#e76f51"])
print(len(brand))
print([round(c, 2) for c in brand[0]])
Вывод
3
[0.16, 0.62, 0.56]

Три цвета бренда готовы к работе: список можно передать прямо в palette= или обернуть в sns.color_palette(), чтобы получить RGB-кортежи для Matplotlib. Если нужно равномерно разложить оттенки по цветовому кругу, пригодится sns.husl_palette(8) — она вернёт восемь максимально различимых цветов, а аргументом задаётся нужное количество.

Что дальше

Арсенал собран: три типа палитр, color_palette() для осмотра, colorblind для безопасности, глобальная set_palette и свои списки цветов. Осталось главное применение цвета — кодировать третье измерение данных: следующий урок разбирает параметр hue, который раскрашивает точки и столбцы по значениям ещё одной колонки. А финальный проект курса соберёт палитры и всё остальное в дашборд аналитики магазина.

Категории отвечают на вопрос «какой», последовательные — «сколько», дивергентные — «в какую сторону от середины».

Что выведет код?

Сначала предскажи ответ в голове — это главный навык программиста.

import seaborn as sns

pal = sns.color_palette("Set2")
print(len(pal))
import seaborn as sns

custom = sns.color_palette(["#e41a1c", "#377eb8", "#4daf4a"])
print(len(custom))
import seaborn as sns

pal = sns.color_palette("colorblind")
print(len(pal))
Проверь себя
0 / 5

1. Что возвращает функция sns.color_palette("Set2")?

2. Цвет должен кодировать плотность населения районов. Какой тип палитры выбрать?

3. Чем палитра colorblind лучше палитры deep для отчёта заказчику?

4. Что произойдёт при вызове sns.countplot(data=df, x="day", palette="Set2") в Seaborn 0.13?

5. Данные: прибыль по месяцам с плюсом и минусом. Какая палитра передаст это лучше всего?

Карточки терминов
Запомнено: 0 / 7
Практика

В редакторе — продажи книжного магазина по жанрам. Постройте barplot среднего объёма продаж по жанрам с палитрой colorblind: разбивка hue="genre" без легенды и заголовок «Продажи по жанрам».

practice.py
Вопросы и ответы по уроку

Как задать свои цвета в Seaborn?

Передайте список цветов прямо в параметр palette=: palette=["#2a9d8f", "#e9c46a", "#e76f51"]. Если нужны RGB-кортежи для Matplotlib, оберните список в sns.color_palette() — она вернёт те же цвета числами от 0 до 1. Для равномерного набора оттенков есть sns.husl_palette(8).

Урок 8: палитры цветов

Какая палитра Seaborn безопасна для дальтоников?

palette="colorblind" — она построена на наборе Okabe-Ito, подобранном различимым при нарушениях цветовосприятия, и не содержит красно-зелёных пар. Включить её для всех графиков сессии можно вызовом sns.set_palette("colorblind").

Чем последовательная палитра отличается от дивергентной?

Последовательная (Blues, viridis) — градиент от светлого к тёмному для величин с порядком: чем темнее, тем больше. Дивергентная (RdBu_r, coolwarm) — два насыщенных края и бледная середина для отклонений от нормы: прибыль и убыток, корреляции от -1 до 1.

Почему palette без hue выдаёт FutureWarning?

В Seaborn 0.13 параметр palette= без hue= считается устаревшим: поведение неочевидно, поэтому библиотека предупреждает FutureWarning, а в 0.14 вызов перестанет работать. Добавьте hue= с колонкой категорий и legend=False, если легенда дублирует подписи оси.

Понравился урок? Сошлитесь на него

«Категории отвечают на вопрос «какой», последовательные — «сколько», дивергентные — «в какую сторону от середины».»

Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.