Отчёт в пятницу, презентация в понедельник, а между ними двадцать картинок, которые должны быть не просто красивыми, но и проверяемыми: наведи курсор и увидь точное значение. Библиотека Plotly для Python решает задачу двумя движениями: готовит фигуру из таблицы значений и отдаёт её в браузер как живой интерактивный объект. Под капотом работает движок на JavaScript, но его не видно: всё описывается на Python. Актуальная версия 7.1.0, а для панелей у того же производителя есть фреймворк Dash 4.4.1. История у проекта предпринимательская: компания Plotly начинала с облачного сервиса графиков, потом открыла движок отрисовки и обросла обёртками для Python и R, и сегодня библиотека это зрелый открытый инструмент с большим сообществом. Разберём её от быстрого наброска до экспорта и панелей, с кодом и практическими приёмами, которые обычно набираются шишками.
Два уровня интерфейса закрывают быстрый набросок и тонкую настройку
Plotly предлагает два лица, и знание обоих экономит часы. Верхний, Plotly Express, строит готовую фигуру из таблицы одной строкой: указал значения, получил график. Нижний, графические объекты, собирает фигуру из отдельных следов и параметров вручную, и именно он даёт контроль над каждой деталью, от толщины линии до подписи деления оси.
Фигура в Plotly это JSON-подобная структура, и Express, по сути, пишет её за вас. Внутри лежат следы с типом и значениями, разметка осей, заголовки и легенда. Express покрывает процентов девяносто насущных задач, а когда его аргументы кончаются, результат конвертируется в объекты нижнего уровня и дорабатывается дальше, без потери уже сделанного.
Философия здесь та же, что у грамотного офиса: сначала черновик, потом вычитка. Быстрый набросок позволяет увидеть форму кривой за минуту, а вычитка на нижнем уровне доводит картинку до товарного вида к презентации.
Поскольку фигура это структура значений, её можно сохранить в JSON и загрузить обратно, а метод to_json помогает передать описание между процессами и даже языками: тот же JSON понимает версия движка на JavaScript и R. Это делает Plotly удобным транспортом графиков между командами аналитиков и фронтенда.
Express превращает таблицу значений в готовую фигуру одной строкой
Главный вход для быстрого графика это модуль px. На вход подаётся таблица в длинном формате, где каждая строка это наблюдение, а цвет, размер и подписи берутся из столбцов по имени:
import plotly.express as px
fig = px.line(
df,
x="month",
y="revenue",
color="region",
markers=True,
title="Выручка по регионам"
)
fig.show()
Одна строка даёт фигуру с легендой по регионам, точками на изломах и всплывающими подсказками при наведении. Цвет распределяется по столбцу region автоматически, палитра подбирается сама, а подписи осей берутся из заголовков столбцов, что избавляет от рутины с наименованиями.
Набор Express покрывает все типовые диаграммы:
- scatter и line рисуют точки и кривые, одиночные и с группировкой по цвету;
- bar строит столбики, в том числе с накоплением и группировкой;
- histogram показывает распределения с автоматической бинировкой;
- box и violin дают статистики по группам с выбросами;
- heatmap отображает матрицы интенсивности от корреляций до календарей;
- choropleth красит географические карты по странам и регионам;
- scatter_3d и line_3d поднимают точки в объём, который вращается мышью.
Тот же вызов умеет дробить картинку на мелкие по столбцу facet_col, раскрашивать по категории, задавать размер маркера отдельным столбцом и вести анимацию по оси времени. Для разведочного анализа это означает, что один вызов px часто заменяет десяток строк возни с осями.
Долгие таблицы с одной строкой на наблюдение это рекомендуемый формат, но и широкие таблицы, где каждая категория это отдельный столбец, принимаются напрямую:
fig = px.line(
df_wide,
x="month",
y=["март", "апрель", "май"],
labels={"value": "выручка", "variable": "месяц"},
)
Параметр labels переименовывает оси на человеческий лад, а параметр category_orders фиксирует порядок столбцов, чтобы апрель не обгонял март в легенде.
Отдельное семейство Express это иерархии: px.sunburst рисует вложенные кольца долей, px.treemap прямоугольники, px.icicle уровни сверху вниз. Для структуры продаж по категориям и регионам одна из этих карт говорит больше, чем десять столбиков.
Графические объекты дают контроль над каждым элементом фигуры
Когда Express упирается в потолок аргументов, фигуру собирают руками. Модуль графических объектов оперирует следами: каждый след это один слой с типом и значениями, а метод update_layout правит всё вокруг, оси, заголовки, поля, легенду.
import plotly.graph_objects as go
fig = go.Figure()
fig.add_trace(go.Scatter(
x=months, y=plan, mode="lines",
name="план", line=dict(color="grey", dash="dot")
))
fig.add_trace(go.Bar(
x=months, y=fact, name="факт",
marker_color="#2c7be5"
))
fig.update_layout(
barmode="overlay",
title="План и факт по месяцам",
yaxis=dict(tickformat="~s"),
)
fig.show()
Кривая плана и столбики факта лягут на один холст, режим overlay наложит их друг на друга, формат оси сократит тысячи до буквы k. Отдельные правки точечны: update_xaxes двигает ось, update_traces меняет следы пачкой, аннотации вешаются по координатам значений.
fig.add_annotation(
x="2026-05", y=peak,
text="пик продаж",
showarrow=True, arrowhead=2,
)
fig.add_hrect(
x0="2026-03", x1="2026-04",
fillcolor="grey", opacity=0.15,
)
Аннотация со стрелкой подсвечивает точку истории, полупрозрачная полоса add_hrect выделяет период акции или простоя. Такие мелочи не меняют чисел, но именно они превращают график в законченный тезис, который не нужно объяснять голосом.
Составные фигуры собирает make_subplots: сетка ячеек с раздельными и совмещёнными осями. Типовой приём отчёта это кривая объёма сверху и столбики разрезов снизу с общей осью времени, и собирается это полутора десятками строк, из которых половина это подписи.
Шаблоны оформления приводят графики к единому виду
У фигур есть темы, и шаблон оформления задаёт единый стиль всем диаграммам сразу: фирменные цвета, шрифты, фон, сетка. В комплекте идут готовые варианты от строгого plotly_white до тёмного plotly_dark, а собственный шаблон собирается один раз и кладётся в общую библиотеку проекта.
import plotly.io as pio
pio.templates["corp"] = go.layout.Template(
layout=go.Layout(
font=dict(family="Inter", size=13),
colorway=["#2c7be5", "#7be58a", "#e5a12c"],
plot_bgcolor="white",
margin=dict(l=60, r=30, t=50, b=50),
)
)
pio.templates.default = "corp"
После этого каждая новая фигура рождается уже в фирменном виде, и отчёт из тридцати графиков выглядит собранно без ручной доводки каждого. Шаблон можно комбинировать с готовым, записав строкой corporate+plotly_white, тогда собственные цвета лягут поверх стандартной геометрии. Для ежемесячных отчётов это то, что отличает аккуратную работу от разрозненных картинок, а смена фирменного цвета задаётся в одном месте и на следующий день распространяется на все тридцать.
Экспорт в HTML картинку и векторный формат под разные задачи
Живой график живёт в браузере, и Plotly умеет выдавать его тремя способами под разные адресаты. Автономный HTML пишется методом write_html и содержит всё внутри, включая движок отрисовки: файл открывается у коллеги без Python и интерактив сохраняется целиком. Для отчётов, где важно не тащить мегабайты, есть облегчённый режим с подключением движка из сети.
fig.write_html("report.html", include_plotlyjs="cdn")
fig.write_html("report_full.html")
Статическая картинка нужна письму и презентации, и здесь работает связка с Kaleido, отдельным инструментом рендеринга без браузера:
fig.write_image("chart.png", width=1200, height=700, scale=2)
fig.write_image("chart.svg")
Параметр scale удваивает плотность пикселей для ретины, SVG снимается для полиграфии и вставки в документы, где вектор не мутнеет при масштабировании. Для ноутбука Jupyter всё проще: fig.show рисует прямо под ячейкой, а в HTML-ноутбуках интерактив встраивается штатно.
Поведением готового HTML управляет словарь config: панель инструментов снимается или урезается, график растягивается по контейнеру, двойной щелчок получает свой смысл. Это мелочь, которая решает, выглядит ли вставка в корпоративный портал самодостаточной или словно приехала из чужого мира.
Связка с Dash собирает интерактивные панели на фреймворке
Одиночный график это половина пользы, полноценная панель требует выпадающих списков, диапазонов дат и пересчёта картинок на лету. Для этого у makers Plotly есть Dash, фреймворк панелей на Flask, React и Plotly, где Python остаётся единственным языком. Свежая ветка 4.4.1 понимает современные Python и компоненты.
from dash import Dash, dcc, html, Input, Output
app = Dash(__name__)
app.layout = html.Div([
dcc.Dropdown(options=regions, value="all", id="region"),
dcc.Graph(id="sales"),
])
@app.callback(
Output("sales", "figure"),
Input("region", "value"),
)
def update(region):
part = df if region == "all" else df[df.region == region]
return px.line(part, x="month", y="revenue")
app.run(debug=True)
Колбэк связывает выбранный регион с фигурой, при смене списка график перерисовывается без перезагрузки страницы. Логика на Python, интерфейс собирается декларативно, а на бою панель работает как обычный веб-сервис за обратным прокси. Для команды аналитиков это означает, что дашборд живёт рядом с кодом расчётов, в одном репозитории и на одном языке.
Набор компонентов закрывает типовую панель: выпадающие списки и слайдеры диапазонов, таблицы значений, поля ввода, переключатели, загрузка файлов и встроенный таймер обновления. Колбэк принимает несколько входов и несколько выходов, поэтому сложная панель с зависимыми списками собирается без единой строки JavaScript. Для больших проектов у фреймворка есть разметка по страницам, превращающая панель в многостраничное приложение с адресами и меню.
Приёмы работы с большими таблицами и типовыми задачами
Плотность точек лечится настройками следов: режим markers с уменьшенной непрозрачностью, выбор формы маркера, а для десятков тысяч точек у движка есть автоматическое прореживание и WebGL-режим scattergl, который рисует миллионы точек без проседания. Гистограммы с включённым накоплением строят сравнения групп без ручной агрегации, а тренд поверх точек добавляется вторым следом линейной регрессии, посчитанной любой библиотекой.
Всплывающая подсказка это тоже часть оформления, и она заслуживает внимания, потому что её видят чаще самой картинки:
fig.update_traces(
hovertemplate="<b>%{x}</b><br>" +
"выручка: %{y:,.0f} руб.<extra></extra>"
)
Шаблон hovertemplate управляет каждым элементом карточки, конструкция с запятой группирует разряды тысяч, а тег extra прячет название следа. Кустомная подсказка с наименованием точки и подписью единиц выглядит как работа студии, а не утилиты.
Типовые ловушки повторяются у всех. Подписи осей остаются машинными, пока их не задали явно. Дата-время требует явного типа оси, иначе подписи съезжают. Диапазон цвета с нулём в значениях растягивается выбросом, и остальная картинка flattenится, лечится логарифмической осью или ручным пределом. Легенда при большом числе категорий полезнее вынести сбоку или в отдельный слой.
Для повторяемости результатов фиксируют версию библиотеки и случайность в расчётах, а описание фигуры сохраняют рядом с отчётом: воспроизвести картинку через полгода можно только при наличии исходной таблицы и кода сборки. Итог для практики. Plotly выбирают, когда графику нужны и жизнь, и тираж: интерактив в браузере, автономный HTML для коллег, статическая картинка для письма, панель на Dash для регулярной работы. Express закрывает будни аналитика за минуты, графические объекты доводят презентационные вещи до блеска, а единый шаблон делает так, что все двадцать картинок отчёта выглядят как одна семья.