Graphviz – mariaż z Pythonem (2/2)

TLDR: Z pomocą pythonowego pakietu graphviz schematy i grafy można tworzyć jeszcze prościej.

Autor zdjęcia: https://pixabay.com/users/stokpic-692575/

Jak już (mam nadzieję) udało mi się pokazać w części 1, Graphviz jest bardzo ciekawym narzędziem do tworzenia grafów i schematów z postaci czysto tekstowej.

Tworzenie wykresów może być jeszcze prostsze (i zautomatyzowane), gdyż istnieje możliwość zaprzągnięcia do pracy pythona.

Jeżeli mamy już zainstalowany sam program, musimy doinstalować pakiet graphviz w pythonie.

pip install graphviz

Po zainstalowaniu dobrze sprawdzić, czy możemy zaimportować pakiet. W 90% przypadków rozwiązanie ewentualnych problemów można znaleźć w tym wątku na stack overflow.

Przykład 1 – Wprowadzanie „Piña colada”

Podobnie jak w „samodzielnej” wersji graphviza, możemy korzystać z dwóch rodzajów schematów `Graph` – grafu nieskierowanego oraz `Digraph` – grafu skierowanego.

from graphviz import Digraph
pina_graph = Digraph(comment='Piña colada')

Powyższe polecenie tworzy pusty graf (z przypisanym komentarzem). Aby dodawać do grafu węzły i krawędzie, wykorzystywane są metody .node() oraz .edge().

pina_graph.node('letter', 'Read the letter')
pina_graph.node('response', 'Write to the author')
pina_graph.node('escape', 'Escape')
pina_graph.node('nothing', 'Do nothing')

Jak widać, w przypadku wierzchołków, podajemy identyfikator node’a (który musi być jednoznaczny) oraz jego opis (który jednoznaczny być już nie musi – dzięki temu możemy mieć na jednym wykresie dwa tak samo podpisane węzły). Możliwe jest także oczywiście dodawanie węzłów z przypisanymi atrybutami:

pina_graph.node('pina', 'Do you like piña coladas?', shape='diamond')
pina_graph.node('rain', 'Do you like getting caught in the rain?', shape='diamond')
pina_graph.node('yoga', 'Are you into yoga?', shape='diamond')
pina_graph.node('brain', 'How much brain do you have?', shape='diamond')
pina_graph.node('sex', 'Do you like making love at midnight in the dunes on the cape?', shape='diamond')
pina_graph.node('author', 'Author is the love that you\'ve looked for', shape='rectangle')

W przypadku krawędzi, podajemy identyfikator początku, końca oraz (jeżeli chcemy) opis:

pina_graph.edge('pina', 'rain', 'yes')
pina_graph.edge('rain', 'yoga', 'yes')
pina_graph.edge('yoga', 'brain', 'no')
pina_graph.edge('brain', 'sex', 'a half')
pina_graph.edge('sex', 'author', 'yes')

pina_graph.edge('pina', 'nothing', 'no')
pina_graph.edge('rain', 'nothing', 'no')
pina_graph.edge('yoga', 'nothing', 'yes')
pina_graph.edge('brain', 'nothing', 'whole')
pina_graph.edge('sex', 'nothing', 'no')

Jeżeli nie chcemy podawać opisu, możemy jednym poleceniem stworzyć kilka krawędzi, metodą edges().

pina_graph.edges([('letter', 'pina'), ('author', 'response'), ('response', 'escape')])

Na podstawie tak dodanych krawędzi można wygenerować plik dot (tak, aby móc go zapisać, bądź umieścić w README.md naszego repozytorium, z wykorzystaniem gravizo )

print(pina_graph.source) 

Co wygeneruje kod w języku dot

// Piña colada
digraph {
	letter [label="Read the letter"]
	response [label="Write to the author"]
	escape [label=Escape]
	nothing [label="Do nothing"]
	pina [label="Do you like piña coladas?" shape=diamond]
	rain [label="Do you like getting caught in the rain?" shape=diamond]
	yoga [label="Are you into yoga?" shape=diamond]
	brain [label="How much brain do you have?" shape=diamond]
	sex [label="Do you like making love at midnight in the dunes on the cape?" shape=diamond]
	author [label="Author is the love that you've looked for" shape=rectangle]
	pina -> rain [label=yes]
	rain -> yoga [label=yes]
	yoga -> brain [label=no]
	brain -> sex [label="a half"]
	sex -> author [label=yes]
	pina -> nothing [label=no]
	rain -> nothing [label=no]
	yoga -> nothing [label=yes]
	brain -> nothing [label=whole]
	sex -> nothing [label=no]
	letter -> pina
	author -> response
	response -> escape
}

Jeszcze prostsze jest wygenerowanie samego obrazka – wystarczy podać nazwę obiektu.

pina_graph

Przykład 2 – Generowanie automatycznego wykresu

Dzięki temu, że wszystko jest ładnie opakowane w pythonowy interfejs, możliwe jest automatyzowanie tworzenia wykresu i wykorzystanie go do wizualizacji przepływu procesu.

Tutaj mała próbka takiego zastosowania – stworzenie prostego wykresu, pokazującego liczby podzielne przez daną liczbę.

number_graph = Digraph(comment='Dzielniki')
for i in range(1, 13):
    number_graph.node(str(i))
    for j in range(1, 13):
        if j%i == 0:
            number_graph.edge(str(i), str(j))

number_graph

Wywołanie tego kodu poskutkuje otrzymaniem takiego obrazka:

Więcej o pakiecie i jego możliwościach można poczytać w jego dokumentacji. Natomiast kod do obu przykładów dostępny jest na githubie

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *