1. Введение

Помните, как вы в очередной раз гуглили, как повернуть подписи осей в Matplotlib на 45 градусов? Или как на созвоне вас просили объяснить «вон ту аномальную точку» на красивом графике Seaborn, и вам приходилось судорожно лезть в Jupyter писать новые фильтры, потому что график — это просто статичная картинка? Знакомая боль.

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

Всё это умеет Plotly.

В этой статье не будет академической воды и бесконечной теории. Мы просто возьмем и пройдем путь от базовых визуализаций до мощных анимаций с ползунками и кнопками. Я собрал концентрат фишек, которые закроют 95% ваших повседневных задач.

Скорее всего, после этого туториала вы больше не захотите писать import matplotlib.pyplot as plt. Поехали!

2. Подготовка и База: Две стороны одной медали

Главное правило хорошего туториала — код должен запускаться у читателя сразу, без танцев с бубном и скачивания мутных CSV-файлов. Поэтому мы будем использовать встроенные датасеты.

Для начала установим всё необходимое. Если вы работаете в Jupyter Notebook или Google Colab, вам понадобятся:

pip install plotly pandas

(Примечание: в современных версиях Colab Plotly уже предустановлен, можно сразу импортировать).

Теперь давайте разберем главный концептуальный секрет Plotly. Вся библиотека строится вокруг двух основных модулей, и важно сразу понимать разницу между ними:

  1. Plotly Express (import plotly.express as px) — это ваша волшебная палочка. Обертка высокого уровня, которая позволяет строить сложнейшие графики в одну строку кода. Она берет на себя всю грязную работу (цвета, легенды, оси) и идеально работает с Pandas DataFrame. В 95% повседневных задач вам нужен именно Express.

  2. Graph Objects (import plotly.graph_objects as go) — это конструктор Lego для хардкорщиков. Здесь вы вручную собираете график по кусочкам: отдельно создаете фигуру (Figure), отдельно добавляете на нее слои-трассы (add_trace), вручную настраиваете макет (Layout). Кода получается больше, но зато вы можете кастомизировать абсолютно любой пиксель.

В этой статье мы будем выжимать максимум из Plotly Express, потому что мы хотим писать меньше, а получать больше. К Graph Objects мы обратимся только тогда, когда нам понадобятся кастомные элементы управления.

Данные для экспериментов

Чтобы не скучать на синтетических [1, 2, 3], возьмем знаменитый датасет Gapminder, который встроен прямо в Plotly. Он содержит исторические данные по странам: ВВП на душу населения, ожидаемая продолжительность жизни и численность населения.

Импортируем библиотеки и смотрим на данные:

import plotly.express as px
import pandas as pd

# Загружаем встроенный датасет
df = px.data.gapminder()

# Посмотрим на первые 5 строк за 2007 год
df_2007 = df[df['year'] == 2007]
print(df_2007.head())

В ответ мы получим аккуратный DataFrame, где каждая строка — это страна в определенном году. Данные готовы.

Теперь давайте нарисуем наш первый график и посмотрим, что такое «интерактивность из коробки».

Фишка №1: Интерактивность «из коробки» (Без усилий)

Давайте построим базовый точечный график (scatter plot). Посмотрим, как зависит ожидаемая продолжительность жизни (lifeExp) от ВВП на душу населения (gdpPercap) в 2007 году.

В Matplotlib нам пришлось бы создавать figure, вызывать scatter, подписывать оси… В Plotly Express это делается одной строкой:

# Строим базовый график
fig = px.scatter(
    df_2007, 
    x="gdpPercap", 
    y="lifeExp", 
    title="ВВП vs Продолжительность жизни (2007)"
)

# Отрисовываем
fig.show()

Если вы запустите этот код, то увидите не просто статичную картинку. Обратите внимание на правый верхний угол графика — там появится неприметная, но невероятно полезная панель инструментов (Modebar).

Что вы получаете бесплатно, написав всего одну строчку кода:

  • Зум (Zoom): Зажмите левую кнопку мыши и выделите прямоугольником скопление точек в левом нижнем углу. График мгновенно приблизится. Чтобы вернуть всё как было, просто кликните по графику два раза.

  • Панорамирование (Pan): Выберите иконку крестика на панели инструментов, и вы сможете “таскать” график мышкой в любые стороны.

  • Сохранение в PNG: Иконка фотоаппарата скачивает то, что вы сейчас видите на экране, в виде аккуратной картинки. Идеально для того, чтобы быстро вставить график в презентацию.

Но и это ещё не всё. Наведите курсор на любую точку. Вы увидите всплывающую подсказку (тултип) с точными значениями X и Y. Это круто, но… недостаточно.

Магия hover_data

Глядя на график, мы видим одинокую точку далеко справа (огромный ВВП, средняя продолжительность жизни). Что это за страна?

В классических библиотеках вам пришлось бы вешать текстовые ярлыки на каждую точку, превращая график в нечитаемую кашу из букв. В Plotly мы просто добавляем данные во всплывающую подсказку!

Давайте прокачаем наш график с помощью параметров hover_name (сделает текст жирным заголовком тултипа) и hover_data (добавит любые нужные колонки из датафрейма):

fig = px.scatter(
    df_2007, 
    x="gdpPercap", 
    y="lifeExp", 
    title="ВВП vs Продолжительность жизни (2007)",
    hover_name="country", # Имя страны будет заголовком подсказки
    hover_data=["continent", "pop"] # Добавляем континент и население
)

fig.show()

Теперь, наведя мышку на ту самую оторвавшуюся точку справа, мы сразу видим: это Норвегия, население около 4.6 млн человек, континент Европа. И при этом сам график остался абсолютно чистым и не перегруженным текстом. Идеально для разведочного анализа данных (EDA)!

Фишка №2: Группировка и стилизация в одну строку

Наш предыдущий график был хорош, но пока это просто скопление одинаковых синих точек. Что, если мы хотим увидеть на нём не две переменные (ВВП и продолжительность жизни), а сразу четыре? В Matplotlib вам пришлось бы писать циклы для перебора категорий, вручную задавать палитры и долго мучиться с легендой.

В Plotly Express всё сводится к добавлению пары аргументов в ту же самую функцию. Встречайте связку color, size и symbol.

И, раз уж мы пишем статью для Хабра, давайте сразу сделаем график стильным и переключим его на тёмную тему!

fig = px.scatter(
    df_2007, 
    x="gdpPercap", 
    y="lifeExp",
    color="continent",      # 1. Красим точки в зависимости от континента
    size="pop",             # 2. Размер точки зависит от населения страны
    size_max=50,            # Ограничиваем максимальный размер "пузырька"
    symbol="continent",     # 3. Разные геометрические фигуры для разных континентов
    hover_name="country",
    template="plotly_dark", # 4. Включаем темную тему!
    title="ВВП, Продолжительность жизни и Население по континентам (2007)"
)

fig.show()

Запускаем код и видим, как скучный scatter plot моментально превратился в сочный многомерный bubble chart (пузырьковую диаграмму). Давайте разберем магию аргументов:

  • color="continent": Plotly автоматически сгруппировал данные по столбцу continent, подобрал контрастную палитру и сам создал аккуратную легенду справа.

    • Скрытая интерактивность: Попробуйте кликнуть на название любого континента в легенде! Plotly скроет эти точки с графика. А двойной клик изолирует выбранный континент, спрятав все остальные. Это невероятно удобно, когда точки перекрывают друг друга.

  • size="pop": Мы добавили третье измерение. Теперь огромные пузыри Азии (Китай и Индия) визуально доминируют на графике, позволяя с первого взгляда оценить масштаб.

  • symbol="continent": Добавляет четвертое измерение (или дублирует color для надежности). Европа теперь представлена ромбами, Азия — кругами, Америка — квадратами. Это отличный тон (accessibility), так как ваш график останется читаемым даже при черно-белой печати или для людей с дальтонизмом.

  • template="plotly_dark": Меняет весь дизайн графика за секунду. Plotly поддерживает множество встроенных тем: plotly_white для строгих отчетов, ggplot2 для фанатов языка R, seaborn и другие.

В итоге, написав всего один вызов функции, мы уместили на плоском экране максимум информации, сделали это красиво и сохранили полную интерактивность.

Фишка №3: Subplots (Фасетные графики) и борьба со «спагетти»

Предыдущий способ с группировкой по цвету отлично работает, когда у вас 3–5 категорий. Но что делать, если их десятки?

Давайте попробуем построить линейный график динамики ВВП (gdpPercap) по годам (year) для всех стран из нашего датасета. Если мы просто укажем color="country", то получим классический «спагетти-график» — нечитаемую кашу из 142 пересекающихся линий, в которой невозможно ничего разобрать.

В Matplotlib для решения этой проблемы пришлось бы создавать сетку сабплотов через plt.subplots(), писать вложенные циклы for, фильтровать данные на каждом шаге и вручную выравнивать оси.

В Plotly Express мы просто добавляем магический аргумент facet_col (или facet_row):

# Строим линейный график для всех стран сразу
fig = px.line(
    df, 
    x="year", 
    y="gdpPercap", 
    color="country", 
    facet_col="continent", # Разбиваем график на колонки по континентам
    facet_col_wrap=3,      # Переносим на новую строку после 3 колонок (для красоты)
    template="plotly_dark",
    title="Динамика ВВП по странам (разбивка по континентам)"
)

# Отключаем легенду, так как 142 названия стран туда всё равно не влезут
fig.update_layout(showlegend=False)

fig.show()

Что произошло под капотом:

  1. Мгновенная сетка: Plotly сам разбил наш огромный датафрейм на 5 частей (по числу континентов) и построил для каждого свой отдельный мини-график. Параметр facet_col_wrap=3 аккуратно перенес лишние графики на новую строку, чтобы они не сплющивались.

  2. Синхронизация осей (Киллер-фича): Если вы запустите этот код и попробуете приблизить (Zoom) какой-нибудь интересный всплеск на графике Европы, вы заметите потрясающую вещь. Оси на всех остальных графиках изменятся синхронно! 3. Чистота кода: Никаких циклов. Никакой возни с осями X и Y для каждого сабплота.

Это невероятно мощный инструмент для разведочного анализа. Вы можете использовать facet_col для одной переменной, а facet_row для другой, создавая целые матрицы графиков (Trellis chart) буквально в полторы строки кода, сохраняя при этом полную интерактивность каждой нарисованной линии.

Фишка №4: Анимации (Вау-эффект)

Статичные графики — это отлично. Фасетные графики — еще лучше. Но если вы хотите сорвать аплодисменты на презентации или заставить заказчика залипнуть в дашборд на 10 минут, вам нужна динамика.

Помните знаменитое выступление Ханса Рослинга на TED, где он показывал эволюцию стран мира в виде движущихся пузырей? С помощью Plotly Express мы воссоздадим этот шедевр.

Для этого нам больше не нужно фильтровать датасет по одному году. Мы берем весь наш df целиком и добавляем всего два магических параметра: animation_frame и animation_group.

# Строим анимированный график по всему датасету (с 1952 по 2007 год)
fig = px.scatter(
    df, 
    x="gdpPercap", 
    y="lifeExp", 
    size="pop", 
    color="continent", 
    hover_name="country",
    animation_frame="year",       # 1. То, что будет меняться (кадры анимации)
    animation_group="country",    # 2. Сущность, за которой мы следим между кадрами
    log_x=True,                   # Логарифмическая шкала для ВВП
    size_max=55, 
    range_x=[100,100000], range_y=[25,90], # 3. ЖЕСТКО ФИКСИРУЕМ ОСИ!
    template="plotly_dark",
    title="Эволюция мира: ВВП vs Продолжительность жизни (1952 - 2007)"
)

fig.show()

Что здесь происходит и почему это круто:

  1. animation_frame="year": Plotly автоматически создает слайдер с годами внизу графика и добавляет кнопки «Play» и «Pause». По клику на Play данные начинают оживать, показывая полет точек сквозь десятилетия.

  2. animation_group="country": Это важнейший параметр. Без него Plotly просто перерисовывал бы новые точки каждый кадр. Указав country, мы говорим библиотеке: «Точка Китая в 1952 году и точка Китая в 1957 году — это один и тот же объект». Благодаря этому Plotly плавно интерполирует (анимирует) движение пузырьков от кадра к кадру, а не заставляет их дергано телепортироваться.

  3. Про-совет (range_x и range_y): Обратите внимание, что мы жестко зафиксировали границы осей. Если этого не сделать, Plotly будет автоматически пересчитывать масштаб осей под каждый кадр. В итоге оси будут “прыгать”, а анимация потеряет всякий смысл. При создании анимаций всегда фиксируйте оси!

Итог: мы написали одну функцию, а получили полноценный интерактивный плеер исторических данных. Никакого Adobe After Effects, только Python!

Фишка №5: Элементы управления (Кнопки и слайдеры без Dash/Streamlit)

Допустим, вы построили отличный график, но теперь заказчик говорит: «А можно добавить кнопочки, чтобы я сам переключал метрики? И ползунок для выбора дат?».

Обычно в этот момент Python-разработчик тяжело вздыхает и идет разворачивать тяжелые фреймворки вроде Dash или Streamlit, писать коллбэки и поднимать сервер. Но Plotly умеет встраивать базовые элементы управления (виджеты) прямо в сам график, используя JavaScript под капотом. Никакого бэкенда не нужно — HTML-файл останется автономным!

Здесь мы немного прикоснемся к концепции Graph Objects (go). Даже если мы создаем график через Express, мы всегда можем «провалиться» на уровень ниже и модифицировать его макет (layout) через методы update_layout или update_xaxes.

Для этого примера датасет с годами нам не подойдет, поэтому возьмем другой встроенный набор данных — котировки акций (px.data.stocks()).

1. Range Slider (Ползунок дат) и кнопки периодов

Это абсолютный маст-хэв для любых временных рядов (time-series). Мы построим график акций и добавим к нему финансовые кнопки масштабирования (1 месяц, 6 месяцев, весь период).

# Загружаем данные по акциям
df_stocks = px.data.stocks()

# Строим базовый линейный график
fig = px.line(
    df_stocks, 
    x='date', 
    y='GOOG', 
    title='Динамика акций Google: Range Slider и кнопки',
    template="plotly_dark"
)

# Добавляем магию управления осью X
fig.update_xaxes(
    rangeslider_visible=True, # Включаем нижний ползунок
    rangeselector=dict(       # Добавляем кнопки быстрого выбора
        buttons=list([
            dict(count=1, label="1 мес", step="month", stepmode="backward"),
            dict(count=6, label="6 мес", step="month", stepmode="backward"),
            dict(step="all", label="Всё время")
        ]),
        bgcolor="#1f2937" # Стилизуем фон кнопок под темную тему
    )
)

fig.show()

Теперь под основным графиком появилась мини-карта (как в финансовых терминалах), за края которой можно тянуть. А в левом верхнем углу — кликабельные кнопки, которые мгновенно зумируют график до нужного периода.

2. Выпадающий список (Dropdown Menu)

А теперь давайте добавим выпадающее меню, которое позволит пользователю на лету менять тип графика, например, переключаться с привычных линий на столбчатую диаграмму (Bar chart).

Для этого используется параметр updatemenus в макете графика:

fig.update_layout(
    updatemenus=[
        dict(
            buttons=list([
                # Кнопка 1: делает график линейным
                dict(label="Линейный график", 
                     method="restyle", 
                     args=["type", "scatter"]),
                     
                # Кнопка 2: превращает график в столбцы
                dict(label="Столбики (Bar)", 
                     method="restyle", 
                     args=["type", "bar"]),
            ]),
            direction="down", # Меню выпадает вниз
            showactive=True,  # Подсвечивать выбранный пункт
            x=0.01,           # Позиция по оси X
            y=1.15            # Позиция по оси Y (чуть выше графика)
        )
    ]
)

fig.show()

Как это работает: Секрет кроется в аргументе method="restyle". Когда пользователь выбирает пункт в меню, Plotly не перерисовывает график с нуля и не обращается к Python. Он просто берет текущие данные и применяет к ним новое свойство (в нашем случае меняет type на scatter или bar) силами браузера.

Помимо restyle (изменение внешнего вида), есть метод update (изменение и данных, и внешнего вида одновременно), с помощью которого в выпадающий список можно зашить переключение между разными колонками датасета (например, переключать график с акций Google на Apple).

Таким образом, мы собрали полноценный интерактивный мини-дашборд в одном окне, не написав ни строчки бэкенд-кода.

Фишка №6: Карты и 3D (Выглядит дорого)

Если после всех предыдущих фишек ваш тимлид, продакт или заказчик всё ещё не сказал «Wow!», пора доставать из рукава козыри. Бизнес обожает карты. Любой отчет с географической картой автоматически выглядит в два раза профессиональнее.

В Plotly Express встроена мощная поддержка карт (через Mapbox или встроенные гео-данные). Давайте вернемся к нашему датасету Gapminder и построим тепловую карту мира (Choropleth map), показав ВВП стран в 2007 году.

Вам не нужно искать шейп-файлы (shapefiles) или координаты полигонов для стран. Plotly всё сделает сам, если у вас есть стандартный трехбуквенный код страны (ISO Alpha), который удачно есть в нашем датасете.

# Строим тепловую гео-карту (Choropleth)
fig = px.choropleth(
    df_2007,
    locations="iso_alpha",   # Колонка с кодами стран (например, RUS, USA)
    color="gdpPercap",       # От цвета зависит ВВП
    hover_name="country",    # При наведении показываем название страны
    color_continuous_scale=px.colors.sequential.Plasma, # Красивая палитра
    projection="natural earth", # Делаем карту плоской, но округлой (а не прямоугольной)
    title="ВВП на душу населения по странам мира (2007)",
    template="plotly_dark"
)

fig.show()

Запустив это, вы получите потрясающую интерактивную карту мира. Вы можете приближать её колесиком мыши, двигать континенты и наводить курсор на страны, чтобы узнать точные цифры.

А что насчет 3D?

Если ваши данные не привязаны к географии, но у вас есть три важных непрерывных признака, переходите в 3D. Это делается буквально заменой слова scatter на scatter_3d:

# Трехмерный график
fig = px.scatter_3d(
    df_2007, 
    x='gdpPercap', 
    y='lifeExp', 
    z='pop',               # Появилась ось Z!
    color='continent', 
    size='pop', 
    hover_name='country',
    template="plotly_dark",
    title="3D: ВВП, Продолжительность жизни и Население"
)

fig.show()

В браузере отрендерится полноценная 3D-сцена. Вы можете вращать этот куб данных мышкой под любым углом, отдалять и приближать его. Главное правило 3D-графиков: используйте их с осторожностью, чтобы не перегрузить пользователя, но для презентаций — это стопроцентный хит.

4. Экспорт и шеринг: Как показать это коллегам?

Вы написали идеальный код, подобрали палитру, настроили анимации и теперь хотите показать результат тимлиду или заказчику. Но у них, скорее всего, не установлен Python, нет Jupyter Notebook, и они точно не будут запускать ваш скрипт через терминал.

Здесь Plotly предлагает два элегантных пути: сохранить график как полноценное интерактивное веб-приложение или сделать качественную статичную картинку для презентации.

Путь 1: Автономный HTML (Сохраняем интерактивность)

Это самая киллер-фича Plotly для коммуникации. Вы можете сохранить свой график в обычный .html файл.

# Сохраняем наш потрясающий 3D-график или анимацию
fig.write_html("my_awesome_graph.html")

В чем магия? Plotly запакует внутрь этого файла и ваши данные, и необходимый JavaScript-код для отрисовки. На выходе получается абсолютно автономный файл размером в пару мегабайт. Вы можете отправить его коллеге в Telegram или по почте.

Коллега просто кликает по файлу, он открывается в любом браузере (Chrome, Safari, Edge), и там работает абсолютно всё: зум, всплывающие подсказки, кнопки, анимации и 3D-вращение. Никаких серверов и бэкенда поднимать не нужно!

Путь 2: Статика для презентаций (PNG, JPEG, SVG)

Иногда интерактивность не нужна. Если вам нужно просто вставить график в PowerPoint, Google Slides или скучный PDF-отчет, график нужно растеризовать.

Для этого в Plotly есть метод write_image(). Но тут есть один важный нюанс, о который часто спотыкаются новички: чтобы превратить веб-график в картинку без открытия браузера, под капотом Python нужен специальный движок. Раньше для этого использовали тяжелый orca, сейчас стандартом является Kaleido.

Сначала установите его через терминал:

pip install -U kaleido

А затем просто сохраняйте графики в любом нужном формате:

# Обычный PNG
fig.write_image("graph.png")

# Хотите идеальное качество для печати? Сохраняем в вектор!
fig.write_image("graph.svg")

# Можно даже настроить масштаб и разрешение на лету
fig.write_image("graph_high_res.png", scale=2, width=1920, height=1080)

Векторный формат (.svg) особенно хорош: вы можете закинуть его в Figma или Illustrator и при необходимости допилить дизайн руками до пиксельного идеала.

5. Заключение: Выводы и немного честности

Мы с вами прошли путь от простого вывода print(df) до интерактивных 3D-сцен и автономных дашбордов в HTML. И всё это без знания фронтенда, JavaScript или сложных фреймворков.

Краткое резюме для закрепления:

  • Plotly Express (px) — ваш лучший друг на каждый день. Позволяет строить сложные, сгруппированные и анимированные графики в 1–2 строки кода.

  • Graph Objects (go) — тяжелая артиллерия. Используйте, когда нужно собрать график по кирпичикам или добавить кастомные кнопки и ползунки.

  • Экспорт в HTML — идеальный способ делиться результатами с бизнесом и коллегами, сохраняя всю магию интерактива.

Ложка дегтя (Когда Plotly вам НЕ подойдет)

На Хабре не принято только хвалить инструменты, поэтому давайте начистоту. У Plotly есть одно слабое место — производительность на экстремально больших объемах данных.

Поскольку Plotly рендерит графики прямо в браузере (используя SVG и WebGL), попытка скормить обыкновенному px.scatter датасет на 5 миллионов строк, скорее всего, намертво повесит вашу вкладку Chrome.

Если ваша задача — нарисовать сырые логи серверов за год или отрисовать миллиард точек на карте, Plotly сдастся. Для таких Big Data задач (где счет идет на десятки миллионов строк) лучше смотреть в сторону Datashader или предварительно агрегировать данные средствами Pandas/PySpark, а уже агрегаты скармливать в Plotly.

Анонсы новых статей, полезные материалы, а так же если в процессе у вас возникнут сложности, обсудить их или задать вопрос по этой статье можно в моём Telegram-сообществе. Смело заходите, если что-то пойдет не так, — постараемся разобраться вместе.

Но для 99% задач аналитика, Data Scientist’а или разработчика — от разведочного анализа до подготовки презентации для стейкхолдеров — Plotly является, пожалуй, самым сбалансированным инструментом на сегодня.

Комментарии (0)