Гайд по библиотеке Plotly
Разработали обширный гайд по библиотеке Plotly в Python. Материал будет полезен как начинающим, так и продвинутым пользователям. Рассмотрим основные и более нетривиальные графики, а также научимся использовать дополнительные возможности Plotly.
Введение в Plotly
Plotly — это мощная библиотека для интерактивной визуализации данных в Python. Основные преимущества:
- Интерактивность: графики можно вращать, выделять части, применять зум, фильтрацию и др.
- Широкий набор типов графиков: от классических линейных до 3D-сеток, тепловых карт, диаграмм разреза и карт.
- Легкость интеграции с Dash (фреймворк для создания веб-приложений), Jupyter Notebook, а также другими средствами BI.
- Гибкость настроек: можно тонко настраивать каждую деталь — цвета, подписи, легенду, оси, фон и т.д.
Установка
!pip install plotly
Примечание: Библиотека Plotly часто уже встроена в различные среды (например, Google Colab). Убедитесь, что у вас установлена актуальная версия.
Ключевой функционал Plotly
Перед погружением в примеры будет полезно познакомиться с основными понятиями и возможностями библиотеки. Это поможет понимать, что происходит в каждом фрагменте кода.
Plotly Express (px) и Graph Objects (go)
- px — упрощённый API для «быстрого старта»: несколько строк — готов интерактивный график (px.bar, px.line, px.scatter_3d, px.choropleth и т. д.).
- go — низкоуровневый API для тонкой настройки: создание go.Figure(), добавление одного или нескольких go.Traces (go.Scatter, go.Bar, go.Surface) и их исправление через fig.update_traces(), fig.update_layout().
- fig = go.Figure() или результат px.* — это контейнер для одного или нескольких «trace» (один trace = одна серия данных, например линия или столбцы).
- fig.add_trace(...) или у px внутри создаются trace автоматически.
Настройка оформления через update_layout / update_traces
- fig.update_layout(...) — глобальные параметры: заголовок, подписи осей (xaxis_title, yaxis_title), отступы (margin), шаблон (template="plotly_white"), легенду, сетку и т. д.
- fig.update_traces(...) — меняет свойства конкретных trace’ов: маркеры, линии, подписи точек (texttemplate, hovertemplate), порядок слоев и т. д.
- Встроенные шаблоны (template): "plotly", "plotly_white", "ggplot2", "seaborn", "simple_white", "presentation".
- color_discrete_sequence для категорий и color_continuous_scale для градиентов. Можно использовать списки из px.colors.sequential, px.colors.diverging или определять свою палитру.
- Hover: инструментальные подсказки выводят подробную информацию при наведении. Кастомизируются через hovertemplate.
- Zoom / Pan: встроенные кнопки позволяют увеличить фрагмент графика и вернуться назад.
Анимация и интерактивные элементы
- animation_frame / animation_group в px автоматически создают слайдер и кнопки Play/Pause.
- Для более сложной навигации используются updatemenus (кнопки) и sliders в fig.layout.
Начальный уровень
На этом уровне мы рассмотрим основные типы диаграмм: линейный график, столбчатая диаграмма, гистограмма, круговая диаграмма и т. д. Эти визуализации подходят для первого знакомства и для решения базовых аналитических задач.
Линейный график (Line Chart)
Описание задачи
Построить временной ряд продаж по месяцам или любым другим периодам. Типовая задача бизнес-аналитики — понять динамику показателя во времени.
Тип графика
Линейный график отлично подходит для отображения изменений во времени или другой последовательной шкале.
import plotly.graph_objs as go # Данные для примера months = ["Янв", "Фев", "Мар", "Апр", "Май", "Июн"] sales = [1500, 1800, 2100, 1600, 2400, 2200] # Создаем объект Figure fig = go.Figure() # Добавляем линейный график fig.add_trace( go.Scatter( x=months, y=sales, mode='lines+markers', name='Продажи', line=dict(width=2), # толщина линии marker=dict(size=6) # размер маркеров ) ) # Оформление fig.update_layout( title="Динамика продаж по месяцам", xaxis_title="Месяц", yaxis_title="Объем продаж", template="plotly_white", # светлая тема оформления font=dict(size=14) ) fig.show()
Столбчатая диаграмма (Bar Chart)
Описание задачи
Сравнить величины (например, количество товаров, проданных в разных регионах) для нескольких категорий.
Тип графика
Столбчатые диаграммы идеально подходят для сравнения категорий (размеры, суммы, количества и т. д.).
import plotly.graph_objs as go regions = ["Север", "Юг", "Восток", "Запад"] values = [150, 200, 100, 180] fig = go.Figure() fig.add_trace( go.Bar( x=regions, y=values, name='Продажи по регионам' ) ) fig.update_layout( title="Сравнение продаж по регионам", xaxis_title="Регион", yaxis_title="Продажи", template="plotly_white", font=dict(size=14) ) fig.show()
Гистограмма (Histogram)
Описание задачи
Посмотреть распределение непрерывной переменной (например, распределение цен товаров или возрастов клиентов).
Тип графика
Гистограммы подходят для отображения распределения данных по интервалам (бинам).
import plotly.express as px import numpy as np # Генерация случайных данных (например, цены) prices = np.random.normal(loc=500, scale=100, size=150) fig = px.histogram( x=prices, nbins=20, # Количество столбцов (бинов) в гистограмме labels={'x': 'Цена'}, title='Распределение цен' ) fig.update_layout(yaxis_title='Количество', template="plotly_white", font=dict(size=14)) fig.show()
Круговая диаграмма (Pie Chart)
Описание задачи
Показать долю категорий от общего объема (например, доли рынка конкурентов, процент затрат на различные статьи расходов и т. д.).
Тип графика
Круговая диаграмма наглядно демонстрирует долевые соотношения.
import plotly.express as px categories = ["Аренда", "Зарплата", "Маркетинг", "Сырье", "Прочее"] costs = [5000, 8000, 2000, 4000, 1000] fig = px.pie( names=categories, values=costs, title="Структура расходов" ) fig.update_traces( textposition='inside', textinfo='percent+label' # Отображаем и проценты, и подпись ) fig.update_layout(template="plotly_white", font=dict(size=14)) fig.show()
Диаграмма рассеяния (Scatter plot)
Описание задачи
Исследовать связь между двумя числовыми показателями (например, цена товара и его рейтинг или продажи и затраты на рекламу).
Тип графика
Диаграмма рассеяния используется для отображения взаимоотношений между переменными и для выявления корреляции.
import plotly.express as px import numpy as np np.random.seed(42) ad_spent = np.random.randint(100, 1000, 50) # Затраты на рекламу sales = ad_spent * 0.8 + np.random.randint(-50, 50, 50) fig = px.scatter( x=ad_spent, y=sales, labels={"x": "Затраты на рекламу", "y": "Продажи"}, title="Зависимость продаж от затрат на рекламу" ) fig.update_layout(template="plotly_white", font=dict(size=14)) fig.show()
Средний уровень
На этом уровне мы рассмотрим более настройки графиков, комбинированные и специализированные виды визуализации, а также работу со слоями данных. Научимся связывать несколько графиков и применять более тонкие настройки стиля.
Комбинированные графики (Subplots)
Описание задачи
Визуализировать несколько связанных метрик на одном изображении с разными типами графиков. Например, сравнить динамику продаж и прибыли во времени, используя линейный график и столбчатую диаграмму.
Тип графика
Используем subplots (комбинацию нескольких графиков в одном поле) для более емкой презентации данных.
import plotly.graph_objs as go from plotly.subplots import make_subplots months = ["Янв", "Фев", "Мар", "Апр", "Май", "Июн"] sales = [1500, 1800, 2100, 1600, 2400, 2200] profit = [400, 500, 600, 380, 750, 670] # Создаем сетку из 1 строки и 2 столбцов fig = make_subplots(rows=1, cols=2, subplot_titles=["Продажи", "Прибыль"]) # Первый график (столбчатая диаграмма для продаж) fig.add_trace( go.Bar(x=months, y=sales, name="Продажи"), row=1, col=1 ) # Второй график (линейный график для прибыли) fig.add_trace( go.Scatter(x=months, y=profit, mode="lines+markers", name="Прибыль"), row=1, col=2 ) fig.update_layout( title="Анализ продаж и прибыли", template="plotly_white", font=dict(size=14) ) fig.show()
Группированные столбчатые диаграммы и столбчатые диаграммы с накоплением (Grouped / Stacked Bars)
Описание задачи
Отобразить сравнение нескольких категорий по разным подкатегориям. Например, продажи разных типов товаров в различных регионах.
Тип графика
Группированные столбчатые диаграммы/ столбчатые диаграммы с накоплением используются для более детального сравнения, когда нужно разбить показатели на подгруппы.
Пример кода (Группированные столбчатые диаграммы)
import plotly.graph_objs as go regions = ["Север", "Юг", "Восток", "Запад"] product_A = [150, 200, 130, 100] product_B = [100, 150, 180, 90] fig = go.Figure() fig.add_trace(go.Bar(x=regions, y=product_A, name="Товар A")) fig.add_trace(go.Bar(x=regions, y=product_B, name="Товар B")) fig.update_layout( barmode='group', # Группированные столбцы title="Продажи товаров A и B по регионам", xaxis_title="Регион", yaxis_title="Продажи", template="plotly_white", font=dict(size=14) ) fig.show()
Пример кода (Столбчатые диаграммы с накоплением)
regions = ["Север", "Юг", "Восток", "Запад"] product_A = [150, 200, 130, 100] product_B = [100, 150, 180, 90] fig = go.Figure() fig.add_trace(go.Bar(x=regions, y=product_A, name="Товар A")) fig.add_trace(go.Bar(x=regions, y=product_B, name="Товар B")) fig.update_layout( barmode='stack', # Накопленные столбцы title="Продажи товаров A и B по регионам (диаграмма с накоплением)", xaxis_title="Регион", yaxis_title="Продажи", template="plotly_white", font=dict(size=14) ) fig.show()
Ящик с усами и скрипичная диаграмма (Box Plot и Violin Plot)
- Ящик с усами (Box Plot) и скрипичная диаграмма (Violin Plot) позволяют детально изучить распределение данных, выявлять выбросы, отображать медиану, квартили и т.д.
- Пример: анализ зарплат сотрудников в разных департаментах.
Тип графика
Подходит для анализа распределений по категориям, оценки смещения данных, выбросов.
import plotly.express as px import numpy as np dept_A = np.random.normal(50000, 5000, 200) dept_B = np.random.normal(52000, 6000, 200) dept_C = np.random.normal(48000, 4000, 200) data = { "Зарплата": list(dept_A) + list(dept_B) + list(dept_C), "Департамент": ["A"] * 200 + ["B"] * 200 + ["C"] * 200 } fig = px.box( data, x="Департамент", y="Зарплата", title="Распределение зарплат по департаментам", points="all" ) fig.update_layout(template="plotly_white", font=dict(size=14)) fig.show()
Пример кода (Скрипичная диаграмма)
fig = px.violin( data, x="Департамент", y="Зарплата", box=True, points="all", title="Распределение зарплат по департаментам (Скрипичная диаграмма)" ) fig.update_layout(template="plotly_white", font=dict(size=14)) fig.show()
Тепловая карта (Heatmap)
Описание задачи
Отобразить интенсивность показателя в двумерной матрице (например, корреляционная матрица признаков).
Тип графика
Тепловые карты позволяют визуально определить зоны высокой или низкой концентрации, выявить паттерны.
import numpy as np import pandas as pd import plotly.graph_objs as go n = 120 sales = np.random.normal(loc=3000, scale=800, size=n) # Продажи ad_spend = sales * 0.3 + np.random.normal(scale=100, size=n) # Расходы на рекламу profit = sales * 0.15 + np.random.normal(scale=50, size=n) # Прибыль clients = np.random.poisson(lam=70, size=n) # Количество клиентов satisfaction = np.random.uniform(low=1, high=5, size=n) # Удовлетворённость df = pd.DataFrame({ "Продажи, тыс. ₽": sales, "Реклама, тыс. ₽": ad_spend, "Прибыль, тыс. ₽": profit, "Клиенты, чел.": clients, "Удовлетворенность, балл": satisfaction }) corr = df.corr().round(2) # Корреляционная матрица fig = go.Figure( data=go.Heatmap( z=corr.values, x=corr.columns, y=corr.index, colorscale='Purples', zmin=-1, zmax=1, colorbar=dict(title="r"), text=corr.values, texttemplate="%{text}", textfont=dict(color="white", size=12) ) ) fig.update_layout( title="Корреляция ключевых бизнес‑метрик", xaxis_title="Метрика", yaxis_title="Метрика", template="plotly_white", font=dict(size=14), margin=dict(l=120, r=120, t=100, b=100) ) fig.show()
Продвинутый уровень
На этом уровне рассмотрим нестандартные возможности Plotly: географические карты, 3D-графики, динамические (анимированные) визуализации, а также настройку интерактивных элементов (слайдеров, кнопок).
Географические карты (Choropleth, Scatter Geo)
Описание задачи
Отобразить метрики (например, продажи, статистику по населению, показателей проникновения продукта) по странам или регионам.
- Choropleth — закрашивание областей (стран/регионов) на карте по интенсивности показателя.
- Scatter Geo — точки/маркеры на карте.
Пример кода (Choropleth с данными о населении стран)
import pandas as pd import plotly.express as px df = px.data.gapminder() fig = px.choropleth( df, locations="iso_alpha", # Колонка с ISO-3 кодом в df color="pop", color_continuous_scale="Purp", hover_name="country", labels={"pop": "Население"}, projection="natural earth", animation_frame='year', title="Население стран мира" ) fig.update_layout( template="plotly_white", font=dict(size=14), margin=dict(l=20, r=20, t=60, b=20) ) fig.show()
Пример кода (Scatter Geo с данными о населении стран)
df = px.data.gapminder() fig = px.scatter_geo( df, locations="iso_alpha", # Колонка с ISO-3 кодом в df color="pop", color_continuous_scale="Purp", hover_name="country", labels={"pop": "Население"}, projection="natural earth", animation_frame='year', title="Население стран мира" ) fig.update_layout( template="plotly_white", font=dict(size=14), margin=dict(l=20, r=20, t=60, b=20) ) fig.show()
3D-графики (3D Scatter, 3D Surface)
Описание задачи
Отобразить многомерные данные (три оси + цвет/размер), или построить 3D-поверхность для наглядного представления функции двух переменных.
Задача: оценить, как меняются основные параметры квартир на рынке Москвы:
import numpy as np import pandas as pd import plotly.express as px # Генерация примерных данных np.random.seed(42) n = 100 # Площадь от 30 до 120 м² area = np.random.uniform(30, 120, n) # Расстояние до центра Москвы distance = np.random.exponential(scale=8, size=n) distance = np.clip(distance, 1, 30) # Цена за м² price_per_m2 = ( 200_000 - distance * 3_000 + np.random.normal(scale=10_000, size=n) ) price_per_m2 = np.clip(price_per_m2, 80_000, 300_000) df = pd.DataFrame({ "Площадь, м²": area, "Удаленность, км": distance, "Цена за м², ₽": price_per_m2 }) fig = px.scatter_3d( df, x="Площадь, м²", y="Удаленность, км", z="Цена за м², ₽", color="Цена за м², ₽", # Раскрашиваем по цене labels={ "Площадь, м²": "Площадь (м²)", "Удаленность, км": "Расстояние от центра (км)", "Цена за м², ₽": "Цена за кв.м (₽)" }, title="3D-анализ рынка квартир Москвы", color_continuous_scale=px.colors.sequential.Purp ) fig.update_layout( template="plotly_white", font=dict(size=12), margin=dict(l=0, r=0, t=50, b=0) ) fig.show()
Пример кода (3D Surface)
import numpy as np import plotly.graph_objs as go # Диапазоны площадей и дистанций x = np.linspace(30, 120, 50) # площадь от 30 до 120 м² y = np.linspace(1, 30, 50) # расстояние от центра от 1 до 30 км # Сетка X, Y = np.meshgrid(x, y) # Цена за м²: Z = 300_000 - 1_000 * X - 2_000 * Y fig = go.Figure( data=[go.Surface( x=X, y=Y, z=Z, colorscale='Purples', cmin=Z.min(), cmax=Z.max(), colorbar=dict(title="Цена за м², ₽") )] ) fig.update_layout( title="3D Surface: Цена за м² в зависимости от площади и удаленности", scene=dict( xaxis=dict(title="Площадь, м²"), yaxis=dict(title="Удаленность от центра, км"), zaxis=dict(title="Цена за м², ₽") ), template="plotly_white", font=dict(size=12), margin=dict(l=50, r=50, t=80, b=50) ) fig.show()
Анимация в Plotly
Описание задачи
Показать изменение данных во времени, создавая анимированную последовательность (например, рост продаж или изменение демографических показателей).
Тип графика
Анимированные графики (animated scatter, animated bar и др.) привлекают внимание и упрощают понимание динамики.
import pandas as pd import numpy as np import plotly.express as px regions = [ "Москва", "Санкт-Петербург", "Новосибирская обл.", "Краснодарский край", "Республика Татарстан", "Свердловская обл.", "Брянская обл." ] district_map = { "Москва": "Центральный", "Санкт-Петербург": "Северо-Западный", "Новосибирская обл.": "Сибирский", "Краснодарский край": "Южный", "Республика Татарстан": "Приволжский", "Свердловская обл.": "Уральский", "Брянская обл.": "Центральный" } years = list(range(2015, 2023)) # Примерные значения по регионам base_pop = { "Москва": 12e6, "Санкт-Петербург": 5.3e6, "Новосибирская обл.": 2.8e6, "Краснодарский край": 5.6e6, "Республика Татарстан": 3.9e6, "Свердловская обл.": 4.3e6, "Брянская обл.": 1.2e6 } base_salary = { "Москва": 65000, "Санкт-Петербург": 55000, "Новосибирская обл.": 40000, "Краснодарский край": 38000, "Республика Татарстан": 42000, "Свердловская обл.": 43000, "Брянская обл.": 35000 } base_unemp = { "Москва": 4.0, "Санкт-Петербург": 4.5, "Новосибирская обл.": 5.5, "Краснодарский край": 6.0, "Республика Татарстан": 5.0, "Свердловская обл.": 5.2, "Брянская обл.": 6.5 } # Генерация данных data = [] for year in years: for reg in regions: pop = base_pop[reg] * (1 + 0.005 * (year - 2015)) salary = base_salary[reg] * (1 + 0.03 * (year - 2015)) \ + np.random.normal(scale=2000) unemp = base_unemp[reg] - 0.1 * (year - 2015) \ + np.random.normal(scale=0.2) data.append({ "Регион": reg, "Округ": district_map[reg], "Год": year, "Население": max(pop, 0), "Зарплата, ₽": salary, "Безработица, %": max(unemp, 0) }) df = pd.DataFrame(data) fig = px.scatter( df, x="Зарплата, ₽", y="Безработица, %", animation_frame="Год", animation_group="Регион", size="Население", color="Округ", hover_name="Регион", log_x=True, range_x=[30000, 90000], range_y=[2, 8], size_max=60, labels={ "Зарплата, ₽": "Среднемесячная зарплата (₽)", "Безработица, %": "Уровень безработицы (%)", "Население": "Население региона", "Округ": "Федеральный округ" }, title="Динамика зарплаты и безработицы по крупным регионам РФ (2015–2022)" ) fig.show()
Дополнительные графики и возможности
Собрали еще несколько интересных вариантов визуализаций, которые могут понадобиться в BI-проектах.
Воронка (Funnel Chart)
Описание задачи
Проанализировать эффективность трех основных каналов привлечения пользователей на мобильное приложение:
На каждом этапе воронки теряется часть аудитории. Задача — сравнить, в каком канале и на каком шаге «проседает» конверсия.
import pandas as pd import plotly.express as px channels = ["Контекстная реклама"] * 6 + ["Социальные сети"] * 6 + ["Email-рассылка"] * 6 stages = ["Показы объявления", "Клики", "Установки приложения", "Регистрация", "Первое действие", "Оплата подписки"] * 3 values = [ # Контекстная реклама 10_000, 8_000, 3_200, 2_400, 1_600, 2_100, # Социальные сети 8_300, 5_500, 2_500, 1_800, 1_200, 1_800, # Email-рассылка 2_700, 4_100, 1_200, 900, 600, 1_400 ] df = pd.DataFrame({ "Канал": channels, "Этап": stages, "Конверсии": values }) # Множество воронок fig = px.funnel( df, x="Конверсии", y="Этап", color="Канал", title="Воронка конверсии по каналам привлечения", labels={"Конверсии": "Количество пользователей", "Этап": "Шаг воронки"} ) fig.update_traces( texttemplate="%{x:.2s}", textposition="inside" ) fig.update_layout( xaxis=dict( tickformat=".2s" ), template="plotly_white", font=dict(size=13), legend_title_text="Канал", ) fig.show()
Солнечные лучи (Sunburst) и дерево (Treemap)
Описание задачи
У интернет-магазина есть три основных категории товаров, внутри каждой — подкатегории и бренды. Необходимо наглядно показать:
- Какие категории приносят больше всего выручки.
- Внутри категории, какие подкатегории лидируют.
- На уровне брендов — распределение продаж.
С помощью Sunburst и Treemap есть возможность сразу погрузиться в каждый уровень и увидеть доли и абсолютные значения.
import pandas as pd import plotly.express as px data = [ ("Электроника", "Смартфоны", "Apple", 120), ("Электроника", "Смартфоны", "Samsung", 90), ("Электроника", "Смартфоны", "Xiaomi", 60), ("Электроника", "Ноутбуки", "Dell", 50), ("Электроника", "Ноутбуки", "HP", 40), ("Электроника", "Ноутбуки", "Lenovo", 30), ("Одежда", "Мужская", "MAAG", 80), ("Одежда", "Мужская", "Nike", 70), ("Одежда", "Женская", "12 STOREEZ", 65), ("Одежда", "Женская", "Lime", 55), ("Дом и сад", "Мебель", "Leroy Merlin", 95), ("Дом и сад", "Мебель", "Hoff", 45), ("Дом и сад", "Текстиль", "Tchibo", 35), ("Дом и сад", "Текстиль", "Leroy Merlin", 25), ] df = pd.DataFrame(data, columns=["Категория", "Подкатегория", "Бренд", "Продажи, млн ₽"]) fig = px.sunburst( df, path=["Категория", "Подкатегория", "Бренд"], values="Продажи, млн ₽", color="Категория", color_discrete_map={ "Электроника": "#636EFA", "Одежда": "#EF553B", "Дом и сад": "#00CC96" }, title="Структура продаж по категориям, подкатегориям и брендам", labels={"Продажи, млн ₽":"Выручка (млн ₽)"} ) fig.update_traces( hovertemplate="<b>%{label}</b><br>Выручка: %{value} млн ₽<br>Доля: %{percentRoot:.1%}", textinfo="label+percent entry" ) fig.update_layout(template="plotly_white", font=dict(size=13)) fig.show()
fig = px.treemap( df, path=["Категория", "Подкатегория", "Бренд"], values="Продажи, млн ₽", color="Категория", color_discrete_map={ "Электроника": "#636EFA", "Одежда": "#EF553B", "Дом и сад": "#00CC96" }, title="Древовидная карта продаж по категориям и брендам", labels={"Продажи, млн ₽":"Выручка (млн ₽)"} ) fig.update_traces( hovertemplate="<b>%{label}</b><br>Выручка: %{value} млн ₽<br>Доля внутри: %{percentParent:.1%}", texttemplate="%{label}<br>%{value} млн" ) fig.update_layout(margin=dict(l=20, r=20, t=60, b=20), template="plotly_white", font=dict(size=13)) fig.show()
Диаграмма Ганта (Gantt chart)
Описание
План разработки и запуска нового веб-сервиса. Необходимо наглядно отобразить:
- Этапы от сбора требований до финального деплоя.
- Задействованные команды (аналитика, дизайн, фронтенд, бэкенд, QA, DevOps).
- Ключевые этапы.
import pandas as pd import plotly.express as px import plotly.graph_objects as go df = pd.DataFrame([ {"Этап": "Сбор требований", "Start": "2025-01-05", "Finish": "2025-01-15", "Команда": "Аналитика"}, {"Этап": "Дизайн интерфейса", "Start": "2025-01-10", "Finish": "2025-01-25", "Команда": "Дизайн"}, {"Этап": "Разработка бэкенда", "Start": "2025-01-20", "Finish": "2025-02-20", "Команда": "Бэкенд"}, {"Этап": "Разработка фронтенда", "Start": "2025-01-25", "Finish": "2025-02-28", "Команда": "Фронтенд"}, {"Этап": "Интеграция компонентов", "Start": "2025-02-15", "Finish": "2025-03-05", "Команда": "Интеграция"}, {"Этап": "Тестирование API", "Start": "2025-03-01", "Finish": "2025-03-10", "Команда": "QA"}, {"Этап": "Тестирование UI", "Start": "2025-03-05", "Finish": "2025-03-15", "Команда": "QA"}, {"Этап": "Деплой и запуск", "Start": "2025-03-16", "Finish": "2025-03-20", "Команда": "DevOps"}, ]) # Диаграмма Ганта через px.timeline fig = px.timeline( df, x_start="Start", x_end="Finish", y="Этап", color="Команда", title="План проекта: разработка и запуск веб-сервиса", labels={ "Start": "Начало", "Finish": "Окончание", "Этап": "Этап проекта" }, color_discrete_map={ "Аналитика": "#636EFA", "Дизайн": "#EF553B", "Бэкенд": "#00CC96", "Фронтенд": "#AB63FA", "Интеграция": "#FFA15A", "QA": "#19D3F3", "DevOps": "#FF6692" } ) fig.update_yaxes(autorange="reversed") # Ключевые этапы с аннотациями milestones = { "2025-01-15": "Утверждена спецификация", "2025-02-20": "Завершен бэкенд", "2025-03-05": "Готова интеграция", "2025-03-20": "Выход в продакшн" } for date, label in milestones.items(): fig.add_vline( x=date, line_dash="dot", line_color="gray", opacity=0.7 ) fig.add_annotation( x=date, y=-0.5, text=label, showarrow=False, yshift=10, font=dict(size=11, color="gray") ) fig.update_layout( template="plotly_white", font=dict(size=12), margin=dict(l=150, r=20, t=80, b=80), legend_title_text="Команда", hoverlabel_align="left" ) fig.show()
Интерактивные элементы: слайдеры, кнопки
Описание задачи
Создать интерактивный дашборд с возможностью может переключения между разными периодами, подмножествами данных и т.д. без изменения исходного кода.
Подход
Слайдеры позволяют двигать «ползунок» вдоль шкалы, меняя отображаемые данные. Кнопки создают набор «сценариев», переключение которых изменяет состояние графика.
Сценарий
Компания хочет посмотреть, как менялись квартальные продажи в разных федеральных округах за период 2018–2022 гг.
– С помощью слайдера выбирается год.
– Кнопки переключают режим отображения столбцов: «Группированные» / «Накопленные»
import pandas as pd import numpy as np import plotly.express as px np.random.seed(0) years = list(range(2018, 2023)) quarters = ['1-й квартал\n(янв–март)', '2-й квартал\n(апр–июнь)', '3-й квартал\n(июль–сентябрь)', '4-й квартал\n(окт–дек)'] districts = ['Центральный', 'Приволжский', 'Уральский', 'Сибирский', 'Южный'] data = [] for year in years: for q in quarters: for d in districts: sales = np.random.uniform(100, 300) # млн ₽ data.append({ 'Год': year, 'Квартал': q, 'Округ': d, 'Продажи, млн ₽': round(sales, 1) }) df = pd.DataFrame(data) # Базовый px.bar с анимацией по годам fig = px.bar( df, x='Квартал', y='Продажи, млн ₽', color='Округ', animation_frame='Год', category_orders={'Квартал': quarters}, labels={ 'Квартал': 'Квартал', 'Продажи, млн ₽': 'Продажи, млн ₽', 'Округ': 'Федеральный округ', 'Год': 'Год' }, title='Квартальные продажи по федеральным округам РФ (2018–2022)', barmode='group', # по умолчанию группированные ) # Кнопки для смены режима отображения столбцов fig.update_layout( updatemenus=[dict( type = "buttons", direction = "right", x=0.1, y=1.12, buttons=list([ dict( label="Группированные столбцы", method="relayout", args=[{"barmode": "group"}] ), dict( label="Накопленные столбцы", method="relayout", args=[{"barmode": "stack"}] ), ]), showactive=True )] ) fig.update_layout( template="plotly_white", font=dict(size=12), ) fig.show()
Когда Plotly Express, а когда Graph Objects
Задача
Понять, какой API выбрать — упрощенный px или go — и как их сочетать.
- px.* подходит для быстрого построения типовых графиков.
- go.Figure дает полный контроль над трейсам, осями, аннотациями.
- Можно строить с помощью px, а затем править через fig.update_traces() / fig.update_layout().
Сравнить два ключевых показателя интернет-магазина по месяцам:
Быстро нарисуем столбцы для количества заказов (px), а затем добавим на этот же график линию для среднего чека с вторичной осью (go).
import pandas as pd import numpy as np import plotly.express as px import plotly.graph_objects as go # Генерация данных np.random.seed(42) rus_months = ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"] dates = pd.date_range("2024-01-01", periods=12, freq="MS") months = [rus_months[d.month - 1] for d in dates] df = pd.DataFrame({ "Месяц": months, "Заказы": np.random.randint(200, 500, size=12), "Средний чек, ₽": np.random.uniform(1500, 3000, size=12).round(0) }) # Быстрое построение графика через Plotly Express fig = px.bar( df, x="Месяц", y="Заказы", title="Динамика заказов и среднего чека в 2024 г.", labels={"Заказы": "Кол-во заказов", "Месяц": "Месяц"}, template="plotly_white" ) # Добавление линии среднего чека fig.add_trace( go.Scatter( x=df["Месяц"], y=df["Средний чек, ₽"], mode="lines+markers", name="Средний чек, ₽", yaxis="y2", marker=dict(size=8), line=dict(dash="dash") ) ) fig.update_layout( xaxis_title="Месяц", yaxis=dict( title="Кол-во заказов", showgrid=True ), yaxis2=dict( title="Средний чек, ₽", overlaying="y", side="right", showgrid=False ), legend=dict(y=1.1, orientation="h"), margin=dict(t=80, b=40, l=60, r=60) ) fig.show()
Оформление
Всплывающие подсказки (hover):