Время прочтения: 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, а также выделение определенных областей для более точного исследования.

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