TLDR: Z pomocą pythonowego pakietu graphviz schematy i grafy można tworzyć jeszcze prościej.
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