Время прочтения: 4 мин.
Думаю, каждый Data Scientist знаком с библиотекой matplotlib, однако это не единственная библиотека для визуализации в python. Бывают такие задачи, когда нужна более “живая” визуализация и нет времени на написание кода для идеального графика с ее помощью. Тогда на ум приходит Plotly (ссылка: https://plotly.com/python/). Plotly — это открытая библиотека, с помощью которой можно быстро строить красивые, а главное интерактивные графики прямо в jupyter-notebook. Данная разработка основывается на JavaScript-библиотеке D3.js. К плюсам данной библиотеки можно отнести связь к одним из удобнейших веб-фреймворком Dash, который появился недавно с помощью создателей Plotly.
Графы, пожалуй, идут в числе первых изображений в matplotlib, которые нуждаются в интерактивности. В нашем случае с помощью интерактивных графов можно получить достаточно много инсайдов из данных. В связку к Plotly мы добавим одну из самых популярных библиотек для работы с графами — NetworkX (ссылка: https://networkx.org/). Данная библиотека создана на python и предназначена для работы с сетевыми структурами и также является бесплатной.
Сочетание Plotly и NetworkX открывает для нас огромные возможности для отличной визуализации графов. В данной статье мы построим визуализацию, на которой будет изображен граф, размеры узла которого будут зависеть от количества его связей, а при наведении курсора на узел будем показывать количеств этих самых связей.
Импортируем нужные библиотеки.
import plotly.graph_objects as go
import networkx as nx
Создадим граф, который возвращает случайный граф, вершины которого будут располагаться в единичном кубе. Два узла соединяются ребром, если расстояние между узлами не превышает определенного радиуса.
G = nx.random_geometric_graph(100, 0.125)
Отрисуем самым обычным способом в NetworkX, чтобы сравнить с графом, который отрисуем чуть позже.
nx.draw(G, node_size = 10)
Соберем координаты для дальнейшего построения связей на графике с помощью Plotly. Добавим их на график.
edge_x = []
edge_y = []
for edge in G.edges():
x0, y0 = G.nodes[edge[0]]['pos']
x1, y1 = G.nodes[edge[1]]['pos']
edge_x.append(x0)
edge_x.append(x1)
edge_x.append(None)
edge_y.append(y0)
edge_y.append(y1)
edge_y.append(None)
edge_trace = go.Scatter(
x = edge_x, y = edge_y,
line = dict(width = 0.5, color = '#888'),
hoverinfo = 'none',
mode = 'lines')
Проделаем аналогичную операцию для узлов.
node_x = []
node_y = []
for node in G.nodes():
x, y = G.nodes[node]['pos']
node_x.append(x)
node_y.append(y)
node_trace = go.Scatter(
x = node_x, y = node_y,
mode = 'markers',
hoverinfo = 'text',
marker = dict(
color = [],
size = 10
),
line_width = 2)
Добавим той самой интерактивности нашему графу. При наведении курсора на узел он будет показывать количество связей с другими узлами. Также размер маркера узла будет зависеть от количества связей. Для некоторых задач это позволит найти наиболее “дружелюбные” элементы графа. В целом, можно добавить очень много полезной и ценной информации, допустим, номер узла или инициалы человека, если использовать графы в контексте задач, связанных с взаимодействием людей.
node_adjacencies = []
node_text = []
for node, adjacencies in enumerate(G.adjacency()):
node_adjacencies.append(len(adjacencies[1]))
node_text.append('Connections: ' + str(len(adjacencies[1])))
node_trace.marker.size = node_adjacencies
node_trace.text = node_text
Далее нарисуем полученный граф и посмотрим на результат.
fig = go.Figure(data=[edge_trace, node_trace],
layout=go.Layout(
title='<br>Тестовый граф для NTA',
titlefont_size = 16,
showlegend = False,
xaxis=dict(showgrid = False, zeroline = False, showticklabels = False),
yaxis=dict(showgrid = False, zeroline = False, showticklabels = False))
)
fig.show()
Данную визуализацию можно сохранить в HTML и изучать уже без использования python, что является огромным плюсом в работе с Plotly, ведь не всегда люди, которым для анализа нужны данные графы, уверенно владеют python. Отдельно стоит отметить верхнюю панель для навигации по графу, она включает в себя все самое нужное: увеличение/уменьшение области просмотра, сохранение участка графика в png, а также выделение определенных областей для более точного исследования.
В конце хочется сказать, что тандем этих двух библиотек позволяет закрыть почти все потребности в повседневной работе с графами.