Если Вы все еще используете Matplotlib для создания графиков в Python, самое время взглянуть на мир с высоты альтернативной библиотеки интерактивной визуализации.
Plotly позволяет создавать красивые, интерактивные, экспортируемые графики с помощью всего нескольких строк кода. Однако без карты подъем в гору Plotly может быть медленным и мучительным.
Вот камни преткновения, которые могут появиться на пути авантюристов, решивших покорить эту гору:
- непонятная начальная настройка для работы оффлайн без аккаунта;
- неимоверное количество строк кода;
- устаревшая документация;
- множество различных инструментов Plotly, в которых можно заблудиться (Dash, Express, Chart Studio и Cufflinks).
Несколько раз попытавшись вскарабкаться на эту гору, я все же нашел карту, снаряжение и короткую тропинку к вершине. В этой статье я укажу вам путь, рассказав как начать работу в оффлайн-режиме, как создавать графики, а потом их корректировать, куда обратиться за помощью и какими инструментами пользоваться.
Plotly
Данная программа была создана одноименной компанией, владеющей множеством программ с открытым исходным кодом для создания интерактивных графиков и чартов. Зарабатывает компания за счет предоставления расширенного пакета функций своих программ. Также за отдельную плату она предлагает настроить Ваш собственный хостинг. Компания базируется в Монреале с офисом в Бостоне.
Plotly.py основывается на JavaScript-библиотеке D3.js. Также в Plotly есть API-обертки для R, Julia и многих других языков программирования. Стоит отметить, что документация представлена не на всех языках.
Примеры библиотек от Plotly
В этой статье мы остановимся на опциях, которые используют Python. Я использую Python 3.7 и последующие версии библиотеки в данном руководстве.
cufflinks 0.15
jupyterlab 0.35.5
plotly 3.8.1
plotly-express 0.1.7
Убедитесь, что используется cufflinks 0.15 (0.13 не очень дружит с последними обновлениями Plotly).
ПРАВКА (май 2020): самая свежая версия Plotly — 4.7.1. Большая часть представленных ниже инструкций все так же применима к последней версии программы. Обратите внимание, что экспресс-модуль импортируется как часть пакета Plotly.
plotly.py
Несмотря на то что написано в некоторых инструкциях, создавать аккаунт для пользования Plotly не нужно, как и не нужно работать в онлайн-режиме.
Установите простой модуль plotly.py с conda или воспользуйтесь
pip install plotly
. Импортируйте модуль и сконфигурируйте его для использования в оффлайн-режиме:
import plotly.offline as py
py.init_notebook_mode(connected=False)
Теперь программа не будет требовать у Вас создать аккаунт. Так мы и преодолели первую преграду на пути к вершине горы Plotly.
Вот пример интерактивного Plotly-графика с земным шаром, которая позволяет изменять тип проекции и расположение с помощью слайдеров. Вы можете сами оценить возможность взаимодействия с данной схемой здесь.
Ниже представлено объемное описание кода, адаптированного из документации, необходимой для создания такого витиеватого графика.
import pandas as pd
import numpy as np
import plotly.offline as py
import plotly.graph_objs as go
import json
py.init_notebook_mode(connected=False)
izip = zip
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/globe_contours.csv')
df.head()
contours = []
scl = ['rgb(213,62,79)','rgb(244,109,67)','rgb(253,174,97)',\
'rgb(254,224,139)','rgb(255,255,191)','rgb(230,245,152)',\
'rgb(171,221,164)','rgb(102,194,165)','rgb(50,136,189)']
def pairwise(iterable):
a = iter(iterable)
return izip(a, a)
i=0
for lat, lon in pairwise(df.columns):
contours.append( dict(
type = 'scattergeo',
lon = df[lon],
lat = df[lat],
mode = 'lines',
line = dict(
width = 2,
color = scl[i]
)
) )
i = 0 if i+1 >= len(df.columns)/4 else i+1
layout = dict(
margin = dict( t = 0, l = 0, r = 0, b = 0 ),
showlegend = False,
geo = dict(
showland = True,
showlakes = True,
showcountries = True,
showocean = True,
countrywidth = 0.5,
landcolor = 'rgb(230, 145, 56)',
lakecolor = 'rgb(0, 255, 255)',
oceancolor = 'rgb(0, 255, 255)',
projection = dict(
type = 'orthographic',
rotation = dict(lon = 0, lat = 0, roll = 0 )
),
lonaxis = dict(
showgrid = True,
gridcolor = 'rgb(102, 102, 102)',
gridwidth = 0.5
),
lataxis = dict(
showgrid = True,
gridcolor = 'rgb(102, 102, 102)',
gridwidth = 0.5
)
)
)
sliders = []
lon_range = np.arange(-180, 180, 10)
lat_range = np.arange(-90, 90, 10)
sliders.append(
dict(
active = len(lon_range)/2,
currentvalue = {"prefix": "Longitude: "},
pad = {"t": 0},
steps = [{
'method':'relayout',
'label':str(i),
'args':['geo.projection.rotation.lon', i]} for i in lon_range]
)
)
sliders.append(
dict(
active = len(lat_range)/2,
currentvalue = {"prefix": "Latitude: "},
pad = {"t": 100},
steps = [{
'method':'relayout',
'label':str(i),
'args':['geo.projection.rotation.lat', i]} for i in lat_range]
)
)
projections = [ "equirectangular", "mercator", "orthographic", "natural earth","kavrayskiy7",
"miller", "robinson", "eckert4", "azimuthal equal area","azimuthal equidistant",
"conic equal area", "conic conformal", "conic equidistant", "gnomonic", "stereographic",
"mollweide", "hammer", "transverse mercator", "albers usa", "winkel tripel" ]
buttons = [ dict( args=['geo.projection.type', p], label=p, method='relayout' ) for p in projections ]
annot = list([ dict( x=0.1, y=0.8, text='Projection', yanchor='bottom',
xref='paper', xanchor='right', showarrow=False )])
# Update Layout Object
layout[ 'updatemenus' ] = list([ dict( x=0.1, y=0.8, buttons=buttons, yanchor='top' )])
layout[ 'annotations' ] = annot
layout[ 'sliders' ] = sliders
fig = dict( data=contours, layout=layout )
py.iplot( fig)
Не уверена, как этот пример сюда запихнуть, не размазав его по нескольким страницам.
Главное, почему стоит избегать работы с “ванильным” модулем plotly.py, — громоздкость данных. Процесс вбивания кода выходит очень длительным и часто приводит к ошибкам. К счастью, из данной ситуации есть два выхода.
Если нам все же не удалось свернуть с тропинки ploty.py, то придется порыться в конструкторе. Официальная документация выглядит красиво, но часто все равно приходится часами копаться на других сайтах в поисках подходящего способа пофиксить код. У Plotly есть свой форум с неплохими советами, но многие образцы кодов не обновлены и не работают в версии 3.0. Поэтому ищите сразу образцы, совместимые с последней версией, или придется переводить их вручную.
Следующие два продукта от Plotly, на которые мы обратим внимание, предлагают высокоуровневые обертки, упрощающие программный интерфейс plotly.py. Они помогут сэкономить время, если вы работаете с библиотекой Pandas. Давайте рассмотрим их поподробнее.
Express
Модуль Plotly Express был выпущен в марте 2019 года и находится в процессе активной разработки. Компания работает над созданием условий поддержки новых графиков и собирается выпустить Plotly 4.0 летом 2019 года.
Express позволяет уменьшить код, необходимый для создания датафреймов Pandas в 10 раз. Загружать свою таблицу нужно в виде “опрятных” данных, где каждый столбец соответствует одной переменной, а каждая строка — одному наблюдению.
Установите Express с помощью
pip install plotly_express
.Чтобы использовать эту библиотеку в записной книжке Jupyter, введите следующий код в командную строку:
jupyter labextension install @jupyterlab/plotly-extension
Данный код позволит создать гистограмму из таблицы с традиционным Express импортом:
import plotly_express as px
px.bar(my_df, x='my_x_column', y='my_y_column')
Вуаля! Вы получили гистограмму по данным таблицы (вставьте свои значения там, где у меня в коде дано “my_”.
Вы можете настроить множество значений. Например, добавьте заголовок, изменив свое определение следующим образом:
px.bar(my_df, x='my_x_column', y='my_y_column', title='My Chart Title")
Если Вы хотите поработать с конкретным параметром, то стоит вернуться к исходному графику Plotly. Допустим, Вы хотите добавить текстовые значения к столбцам в гистограмме. Для этого Вам нужно сохранить оригинальную диаграмму и указать свойства данных. Вот как это сделать:
_my_fig = px.bar(my_df, x='my_x_column', y='my_y_column', title='My Chart Title')
_my_fig.data[0].update(
text=my_df['my_y_column'],
textposition='inside',
textfont=dict(size=10)
)
_my_fig.iplot()
Внимание: я нашел документацию Express! Она не отобразилась у меня на первой странице поиска в гугле, поэтому я не сразу смог ее прикрепить. Теперь она есть. Всегда пожалуйста!
Express позволяет быстро создавать разного вида диаграммы, но доступны могут быть не те, что Вам требуются. Например, нормальную гистограмму с накоплением вы сейчас врядли сможете собрать. А если очень надо, то придется подниматься в гору по другой тропинке — в этот раз с Cufflinks.
Cufflinks
Cufflinks очень похож на Express тем, что является оберткой интерфейса Plotly, позволяющей упростить работу с Pandas. Cufflinks — сторонняя программа с открытым исходным кодом, которая существует уже более четырех лет.
Установите ее с помощью
pip install cufflinks
.Импортируйте модуль и настройте файл для автономного использования.
import cufflinks as cf
cf.set_config_file(offline=True)
С Cufflinks для создания многих видов диаграмм нужна лишь одна строчка кода. К примеру, сделать гистограмму с накоплением с этой библиотекой проще простого.
Пример гистограммы с накоплением, созданной с помощью Cufflinks.
А вот и сам код:
df = pd.DataFrame(np.random.rand(6, 3), columns=['A', 'B', 'C'])
df.iplot(kind='bar', barmode='stack', title='Stacked Bar Chart with Random Data')
Обратите внимание, что для создания диаграмм с помощью Cufflinks Вам нужно использовать
.iplot()
.Как и Express, Cufflinks возвращает исходные данные, чтобы Вы могли вносить мелкие поправки. Но в отличие от Cufflinks, Вам нужно уточнить переменную
asFigure=True
, чтобы вернуть информацию. После этого можно обновить график точно так же, как в Express. Вот как это будет выглядеть, если Вы захотите изменить название и диапазон осей. my_fig = df.iplot(kind='bar', barmode='stack', title='Stacked Bar Chart with Random Data', asFigure=True)
my_fig.layout.yaxis = dict(title='Members', range=[0, 600])
Вот документация Cufflinks.
К сожалению, Cufflinks тоже имеет свои лимиты. Например, с помощью этой библиотеки нельзя создать график рассеяния с географическими координатами.
Сравнение трех вариантов
Далее Вы можете наблюдать сравнение кода со схожей структурой для графиков, созданных с помощью plotly.py, Express и Cufflinks.
plotly.py
Пример диаграммы рассеяния, выполненной с plotly.py
fig = {
'data': [
{
'x': df2007.gdpPercap,
'y': df2007.lifeExp,
'text': df2007.country,
'mode': 'markers',
'name': '2007'},
],
'layout': {
'title': "Example Scatter Plot with Vanilla plotly.py"
}
}
py.iplot(fig)
Express
Пример диаграммы рассеяния, выполненной с Plotly Express
px.scatter(
df2007,
x="gdpPercap",
y="lifeExp",
title='Example Scatter Plot with Plotly Express'
)
Выглядит просто и лаконично! Форматирование по умолчанию немного отличается, а названия осей генерируются автоматически. Теперь предлагаю взглянуть на тот же график в Cufflinks.
Cufflinks
Пример диаграммы рассеяния, выполненной с Cufflinks
df2007.iplot(
kind='scatter',
mode='markers',
x='gdpPercap',
y='lifeExp',
title='Example Scatter Plot with Cufflinks'
)
Код похож на Express, но у графика немного другие значения по умолчанию. Определенно, с Express и Cufflinks Вам не придется часами выстукивать коды, что особенно важно при создании более сложных графиков.
Давайте посмотрим, как можно вернуть и обратиться к основной информации.
Обновление графиков Cufflinks и Express
Давайте перейдем к макету графика, созданного с Cufflinks, и добавим названия осей.
Пример диаграммы рассеяния, выполненной с Cufflinks — Доступ к исходному графику
fig = df2007.iplot(
kind='scatter',
mode='markers',
x='gdpPercap',
y='lifeExp',
asFigure=True,
title='Example Scatter Plot with Cufflinks - Access Underlying Figure'
)
fig.layout.xaxis.title = "GDP per Capita"
fig.layout.yaxis.title = "Life Expectancy"
fig.iplot()
Вот как сделать то же самое с Express. Не забывайте, что в данной библиотеке не нужно уточнять
asFigure=True
.Пример диаграммы рассеяния, выполненной с Plotly Express — Доступ к исходному графику
fig = px.scatter(
df2007,
x="gdpPercap",
y="lifeExp",
title='Example Scatter Plot with Plotly Express - Access Underlying Figure'
)
fig.layout.xaxis.title = "GDP per Capita"
fig.layout.yaxis.title = "Life Expectancy"
fig.iplot()
Вы можете обратиться к исходным данным, чтобы добавить текстовые метки следующего вида:
fig.data[0].update(
text=df2007['gdpPercap'],
textposition=’inside’,
textfont=dict(size=10)
)
Что выбрать: Plotly.py, Express или Cufflinks
Выбирать всегда сложно. Один раз я думал, что работал над частью проекта в Express, а потом понял, что это был Cufflinks!
Мне очень нравится выражение из «Zen of Python»: «Должен существовать один и, желательно, только один очевидный способ сделать это.” Как только появляются варианты — появляются и необходимость долгого поиска информации, и усталость от необходимости выбирать, и ошибки.»
К сожалению, ни один высокоуровневый API на данный момент не дает возможность создавать графики любого типа. Однако лично я точно постараюсь максимально избегать использования «ванильного» plotly.py и предпочту Cufflinks или Express.
Советую лишний раз заглянуть в документацию Express и Cufflinks, прежде чем создавать диаграмму. Не забывайте, что Express использует «опрятные» датафреймы, в то время как Cufflinks в этом плане более гибкий. Пользуйтесь той библиотекой, которая отвечает Вашим потребностям и обладает предпочтительным для Вас форматом.
Форматирование по умолчанию у двух библиотек может сильно отличаться. Например, создав датафрейм со случайными данными для столбцов X, Y и Z и используем следующий код, в Cufflinks мы получим следующую диаграмму:
df.iplot(kind=’scatter’, mode=’markers’, x=’X’, y=’Y’, title=’Random Data’, categories=’Z’)
Диаграмма рассеяния по умолчанию с Cufflinks
А вот что мы получим с Express-кодом:
px.scatter(df, x=’X’, y=’Y’, color=’Z’, title=’Random Data’)
Другие пресеты с Express
Заметная разница!
Сохранение файлов
Закончив работы с диаграммой, Вы можете навести на нее мышку и щелкнуть по значку камеры, чтобы экспортировать ее в формате .png, или нажать “Экспортировать в plot.ly, чтобы сохранить интерактивное изображение на сервер Plotly. Помимо этого, Вы можете скачать файлы в интерактивном HTML-формате следующим образом:
py.offline.plot(my_fig, filename=’my_example_file.html’)
Если нужны другие форматы изображения, Вы можете воспользоваться пакетом orca и скачивать файлы в форматах .png, .jpg и .pdf. Данный пакет на данный момент недоступен на pypi.org, поэтому установить его с помощью pip не получится. Вы можете управлять пакетом с помощью conda или установить ОС-специфичную версию orca со страницы GitHub. После этого Вам не нужно будет импортировать библиотеку orca. Узнать больше о программе orca можно здесь.
Вот код для создания png-файла после установки orca:
import plotly as plotly
plotly.io.write_image(fig, file='my_figure_file.png', format='png')
Как видите, вытянуть свои графики из Plotly можно несколькими разными способами.
Предлагаю кратко пробежаться по еще двум компонентам экосистемы Plotly, чтобы Вы поняли что есть что.
Dash
С Plotly Dash Вы можете создавать дашборды для своей команды или для других людей. Есть версия с открытым кодом доступа, у которой к 1 мая 2019 года насчитывалось практически 9000 звезд GitHub. Plotly также предлагает целый ряд дополнений. Может, в будущем я напишу статью и об этом. Подписывайтесь, чтобы не пропустить.
Chart Studio
Plotly Chart Studio позволяет легко создавать и редактировать графики в браузере. Plotly рекламирует данную программу как “самый умный редактор для создания D3.js- и WebGL-диаграмм. Не надо ничего кодировать вручную”. Есть бесплатная версия, но если хотите сохранить свои графики, то придется отдать 99$ за год использования.
А теперь, когда мы уже добрались до вершины Plotly, давайте быстро пробежимся по другим горам визуализации данных в диапазоне Python.
Бонус: другие варианты библиотек визуализации данных от Python
Я не собирался в этой статье рассказать обо всех на свете программах для визуализации данных, но все же хочу упомянуть несколько довольно важных программ, о которых специалисты по работе с данными должны знать. Так Вы сможете максимально полно познакомиться с территориями, с которыми, возможно, придется работать.
Хотите делать графики по старинке — обратитесь к “ванильной” библиотеке Matplotlib API.
Pandas Matplotlib позволяет создавать неплохие простенькие графики. Может создавать стандартные Matplotlib объекты.
Seaborn — отличная высокоуровневая обертка, основанная на Matplotlib, которая позволяет создавать различные графики визуализации статистических данных. К сожалению, из-за довольно старой базы Matplotlib, использовать ее не очень удобно.
Bokeh — конкурент Plotly. Программа с открытым исходным кодом, интерактивная, работает с Python.
Holoviews — высокоуровневая обертка, работающая с Matplotlib, Bokeh, а теперь и с Plotly. Знаю ребят, которые пользуются именно ей.
Специалистам, работающим с языком R, нравится использовать Shiny от RStudio. Оно позволяет пользователям R создавать интерактивные визуализации для веб-приложений.
Tableau и Microsoft PowerBI — две популярные опции с системой перетаскивания данных визуализации, которые работают с Python. Tableau — очень даже хорошая библиотека, но за нее придется заплатить, если не хотите, чтобы Ваша работа была в открытом доступе.
На мой взгляд, PowerBI обладает менее интуитивно понятным интерфейсом, но программа все равно очень мощная и популярная.
Большинство ПО для создания интерактивных графиков используют библиотеку D3.js. Она очень популярна.
Выводы и полезные ресурсы
Если Вы являетесь специалистом по работе с данными, советую обратить внимание на Plotly. Эта программа обладает современными инструментами для создания интерактивных диаграмм. С вершины этой горы кажется, что такую мощную махину, как Plotly, в ближайшее время точно не сможет обогнать.
Возможно, когда-нибудь появится универсальная библиотека, позволяющая создавать все, что захотите, используя высокоуровневые API-опции Plotly. А пока, если хотите сэкономить время и сделать крутые графики, предлагаю обращаться к Pandas с Cufflinks или Express.
- Will Koehrsen рассказывает как начать пользоваться Cufflinks.
- Jon Mease рассказывает что можно сделать с plotly.py v3.0 на JupyterLab
Совет: когда используете в графиках цвет, не забывайте про людей с дальтонизмом. Воспользуйтесь палитрой, удобной для дальтоников. Я использую палитру от ggplot.
Образец цветов
color_list = ["#E69F00", "#56B4E9", "#009E73", "#F0E442", "#D55E00", "#0072B2", "#CC79A7"]
Узнайте подробности, как получить востребованную профессию с нуля или Level Up по навыкам и зарплате, пройдя платные онлайн-курсы SkillFactory:
- Курс по Machine Learning (12 недель)
- Обучение профессии Data Science с нуля (12 месяцев)
- Профессия аналитика с любым стартовым уровнем (9 месяцев)
- Курс «Python для веб-разработки» (9 месяцев)