Настройка графика: подписи, легенда, сетка
Сырой график — это полуфабрикат. Подписи, легенда и аннотации превращают его в сообщение.
«График без подписей осей — это загадка. Зритель не обязан угадывать, что значат числа».
График из коробки рисует данные, но не объясняет их. Профессиональная визуализация всегда несёт контекст: что на осях, в каких единицах, что значат цвета, где главная точка. Matplotlib даёт полный набор методов на объекте Axes.
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(months, revenue, marker="o", label="Выручка")
ax.plot(months, costs, marker="s", label="Затраты")
ax.set_title("Выручка и затраты за полугодие")
ax.set_xlabel("Месяц")
ax.set_ylabel("Тыс. руб.")
ax.set_ylim(0, None) # ось Y от нуля — честно
ax.grid(True, alpha=0.3) # лёгкая сетка
ax.legend() # легенда по label=...
# аннотация ключевой точки
ax.annotate("Пик продаж", xy=(months[3], revenue[3]),
xytext=(months[3], revenue[3] + 20),
arrowprops=dict(arrowstyle="->"))
fig.tight_layout()
fig.savefig("report.png", dpi=150)
Обратите внимание на set_ylim(0, None): ось Y начинается с нуля — это вопрос честности, к которому мы вернёмся в разделе про искажения. tight_layout() убирает обрезание подписей.
Почему на оформление вообще стоит тратить силы? Потому что график почти всегда живёт дольше и дальше, чем код, который его породил: его вставят в слайд, отправят в чат, распечатают в отчёт — без вас рядом, чтобы объяснить. График, оторванный от контекста, должен сам отвечать на три вопроса: что по осям, в каких единицах и какой здесь главный вывод. Поэтому заголовок лучше делать не описательным («Выручка по месяцам»), а выводным («Выручка выросла на 58% за полугодие»): тогда зритель уносит мысль, а не просто факт наличия графика. Хороший заголовок — это короткое предложение, а не ярлык.
Полезно знать чуть больше методов настройки. ax.set_xticks() и ax.set_xticklabels() управляют делениями вручную — например, повернуть длинные подписи: ax.tick_params(axis="x", rotation=45). ax.axhline(y=0) и ax.axvline() рисуют опорные линии (ноль, целевое значение, среднее). ax.text() ставит произвольную надпись в координатах данных, а transform=ax.transAxes переключает её в относительные координаты 0..1, удобные для пометок в углу. Форматирование чисел на оси задаёт ax.yaxis.set_major_formatter() — так превращают «1000000» в «1 млн» или добавляют знак процента. Эти мелочи и отличают черновик от графика, который не стыдно показать.
Как работает под капотом
Каждый set_* меняет свойство соответствующего artist (заголовка, оси, сетки). Легенда строится из пар «artist + label»: вы задаёте label= при рисовании, а legend() собирает их. Аннотация — это текстовый artist плюс стрелка-artist с координатами в системе данных. savefig запускает backend (Agg для PNG), который растеризует дерево объектов.
Аннотации часто ставят на экстремумы. Найдём их вручную — это и есть «куда поставить стрелку».
# Находим пик и провал в ряду — кандидаты на аннотацию
months = ["янв", "фев", "мар", "апр", "май", "июн"]
revenue = [120, 135, 150, 190, 175, 160]
peak_i = revenue.index(max(revenue))
low_i = revenue.index(min(revenue))
print("Пик:", months[peak_i], max(revenue))
print("Провал:", months[low_i], min(revenue))
# рост месяц к месяцу
for i in range(1, len(revenue)):
delta = revenue[i] - revenue[i - 1]
sign = "+" if delta >= 0 else ""
print(months[i], sign + str(delta))
«Попробуй сам ▶» — экстремумы и дельты, которые вы посчитали, обычно и подписывают на графике стрелками.
Частые ошибки
График без подписей осей и единиц. Легенда, перекрывающая данные (используйте loc= или bbox_to_anchor). Слишком плотная сетка, забивающая данные. Подписи обрезаны — забыли tight_layout(). Чрезмерные аннотации — каждая точка подписана.
Добавим типичные огрехи оформления, которые портят даже верный по сути график. Описательный заголовок вместо выводного: «График выручки» ничего не сообщает — лучше вынести в заголовок сам вывод. Нечитаемые подписи оси X, налезающие друг на друга — их нужно повернуть (rotation=45) или перейти на горизонтальный barh. Дублирование информации: и легенда, и прямые подписи у линий одновременно — выберите что-то одно, прямые подписи у концов линий часто читаются лучше легенды. Слишком мелкий шрифт для слайда или печати — то, что разборчиво на экране ноутбука, исчезает на проекторе; задавайте размер шрифта осознанно. Контейнерные «рамки» (верхняя и правая линии, spines) добавляют визуального шума — их часто убирают через ax.spines["top"].set_visible(False). И сохранение в низком DPI: график для отчёта в 72 dpi выглядит мыльным, для печати нужно 150–300.
Best practices
- Обязательны: заголовок-вывод, подписи осей, единицы измерения.
- Сетка — бледная (
alpha=0.3), чтобы не спорить с данными. - Аннотируйте только ключевые точки — 1–2, не все.
- Сохраняйте в высоком DPI для отчётов (
dpi=150и выше).
Итог: вы умеете делать график читаемым. В следующем разделе пройдём по конкретным типам графиков и научимся выбирать их осознанно.