Нарисовать граф с Graphviz в Jupyter Notebook

Однажды мне понадобилось нарисовать граф в Jupyter Notebook. Когда дело доходит до визуализации графов,  то проходит ассоциация с библиотекой GraphViz. В первый раз мы с ней познакомились во время решения задач mlcource.ai от ODS — нужно было нарисовать итоговое дерево решений. Но вообще славный GraphViz рисует не только деревья, а в принципе любые графы.

Вообще GraphViz не совсем питон-пакет, поэтому его установка чуть-чуть муторней, чем просто !pip install graphviz. Установка GraphViz для Anaconda 3 в Windows 10 выглядит следующим образом (по крайней мере, мне помогло).

Вместо graphviz ставим анакондовский пакет

 
 
  1. !conda install python-graphviz

python-graphviz подтягивает вместе с собой сам graphviz и создает bin-файлы, без который вся эта магия не работает.

bin-файл родится в папке …\Anaconda3\Library\bin\graphviz, где вместо «…» — ваше местоположение Анаконды.

Если больше ничего не делать, то запуск отрисовки графа будет выдавать такую ошибку:

 
 
ExecutableNotFound: failed to execute ['dot', '-Tsvg'], make sure the Graphviz executables are on your systems' PATH

Поэтому добавляем папку с бинарными exe-файлами в переменные PATH

 
 
import sys
sys.path #можно посмотреть что в PATH
graphviz_path = '...\\Anaconda3\\Library\\bin\\graphviz'  #не забыть поправить ... и поставить двойные юниксовые слеши
sys.path.insert(0, graphviz_path)
#sys.path.remove(graphviz_path) - если что-то пошло не так и путь нужно удалить
!dot -V  #проверить, что всё работает - должен вывести версию graphviz

Если все работает, то можно попробовать отрисовать какой-нибудь граф. Если немного лениво сочинять свой, то можно взять из примеров в документации (кстати, официальный сайт тут — https://www.graphviz.org/). Можно, например, нарисовать маленький граф про Короля Артура.

Код очень простой:

 
 
from graphviz import Digraph
dot = Digraph(comment='The Round Table')
dot.node('A', 'King Arthur')
dot.node('B', 'Sir Bedevere the Wise')
dot.node('L', 'Sir Lancelot the Brave')
dot.edges(['AB', 'AL'])
dot.edge('B', 'L', constraint='false')
dot

Digraph создает ориентированный граф (Graph создаст неориентированный граф).  Затем создаем вершины и каждой задаем название и подпись, потом создаем ребра — по одному или «пачкой».

Соответственно, можно нарисовать такой граф по матрице смежности. Например, таким не очень питон-кодом (можно и поизящней), но в котором наглядно виден процесс:

 
 
import numpy as np
from graphviz import Graph
adjmatrix = np.array([[1, 2, 3], [0, 2, 0], [0, 3, 4]])
N = adjmatrix.shape[0]
M = adjmatrix.shape[1]
g = Graph(comment='FromMatrix')
for i in range(N):
    g.node('Node'+str(i), 'Node'+str(i))
    for j in range(M):
        g.edge('Node'+str(i), 'Node'+str(j), label=str(adjmatrix[i][j]))
    
g

Ноутбук: на github.

Добавить комментарий