Graphviz er et værktøj til at tegne grafer. Graphviz bruger en layoutalgoritme til at tegne grafen, så du kun behøver at definere knuder og kanter i grafen. Dette er en meget kort gennemgang af Graphviz, se mere på manualsider og http://www.graphviz.org/.

Eksempel: Simpel tilstandsmaskine

Vi vil nu gennemgå et par eksempler på definitionen af en simpel tilstandsmaskine i Graphviz. Vi starter med følgende definition:

digraph {
  rankdir = LR;
  node [shape=circle];
  start-> q1;
  q1 -> q1 [label="a"];
  q2 -> q2 [label="a"];
  q1 -> q2 [label="b"];
  q2 -> q1 [label="b"];
}

Der giver grafen:

En digraph definition er en definition af en directed graph. På den simpleste form består definitionen af en definition af hvilke kanter der er i grafen, f.eks. linjen q1 -> q2 [label="a"]; ovenfor, der definerer at der går en kant fra q1 til q2 og der er et label på kanten med teksten "b". Linjen rankdir = LR; angiver at vi gerne vil have placeret knuderne ved siden af hinanden (left-to-right) og ikke under hinanden (default er TB: top-to-bottom). Linjen node [shape=circle]; angiver at knuderne skal tegnes som cirkler (som standard bruges ellipser).

Vi kan dog pynte lidt på denne graf. F.eks. vil vi gerne angive hvilke af knuderne der er accepterende tilstande. Dette gøre ved en annotering til den enkelte knude, hvor det angives at knuden skal tegnes som en dobbelt-cirkel:

q2 [shape=doublecircle];

En anden ting vi gerne vil ændre på er begyndelsespunktet for tilstandsmaskinen, der lige nu er angivet med en start-knude. Vi vil i stedet angive det med en pil på den første tilstand (q1). Dette kan vi opnå ved at skjule start knuden (vi gør den til et hvidt punkt):

start [color=white, shape=point];

Ved at tilføje disse to linjer nåde vi frem til denne definition:

digraph {
  rankdir = LR;
  node [shape=circle];
  start [color=white, shape=point];
  q2 [shape=doublecircle];
  start-> q1;
  q1 -> q1 [label="a"];
  q2 -> q2 [label="a"];
  q1 -> q2 [label="b"];
  q2 -> q1 [label="b"];
}

Som resulterer i:

Render .dot-filer

For at rendere dine dot-filer til billeder der kan inkluderes i din rapport skal du bruge kommandolinjeværktøjet "dot". For at lave en figur tegnet i vektor grafik (PDF) benyttes kommandoen:

dot -Tpdf example1.dot  -o example1.pdf

dot2texi - Graphviz i LaTeX

For at bruge Graphviz direkte fra LaTeX kan man benytte "dot2tex"-pakken. På Debian og Ubuntu kan du installere den direkte med:

sudo apt-get install dot2tex

Preamble

I din LaTeX fil skal du tilføje følgende i din preamble:

\usepackage[dot, autosize, outputdir="dotgraphs/"]{dot2texi}
\usepackage{tikz}
\usetikzlibrary{shapes}

hvor outputdir angiver hvor du vil have placeret filerne, mappen skal eksistere i forvejen, og husk den sidste skråstreg)

dot2tex environmentet

For at indtaste grafer direkte i LaTeX kan du nu nøjes med at skrive:

\begin{dot2tex}
digraph {
  rankdir = LR;
  node [shape=circle];
  start [color=white, shape=point];
  q2 [shape=doublecircle];
  start-> q1;
  q1 -> q1 [label="a"];
  q2 -> q2 [label="a"];
  q1 -> q2 [label="b"];
  q2 -> q1 [label="b"];
}\end{dot2tex}

Nu behøver du ikke længere bruge tid på at kalde graphviz manuelt eller inkludere pdf-filerne.

Matematik-mode i labels

Med dot2tex kan du også skrive arbitrære formler i din LaTeX-kode, det kræver blot at du sætter

texmode="math"

på de elementer hvor du vil have det. Her er eksemplet ovenfor udvidet så teksterne får det rigtige skriftsnit:

\begin{dot2tex}
digraph {
  rankdir = LR; 
  node [shape=circle, texmode="math"];
  edge [texmode="math"];
  start [color=white, label="", shape=circle, width=0, height=0];
  1 [label="q_1"];
  2 [label="q_2", shape=doublecircle];
  start-> 1;
  1 -> 1 [label="\texttt{a}"];
  2 -> 2 [label="\texttt{a}"];
  1 -> 2 [label="\texttt{b}"];
  2 -> 1 [label="\texttt{b}"];
}
\end{dot2tex}

Vi er nu nået frem til dette udseende for tilstandsmaskinen:

Oversættelse

For at kunne bruge dot2tex til at automatisk kunne oversætte dine filer skal du tilføje "--shell-escape" som parameter til latex (eller pdflatex). Dette giver LaTeX-dokumenter til at kalde arbitrære programmer på dit system og kan udgøre en sikkersrisiko. Derfor anbefales det ikke at gøre det generelt i din editor, hvis der er andre muligheder.

I Emacs kan du nøjes med at tilføje disse linjer til de LaTeX-filer hvor der er behov for dot2tex:

%%% Local Variables: 
%%% mode: latex
%%% tex-command: "latex --shell-escape" 
%%% End: 
alathon
Offline
Sv: Graphviz

Lige et par fif, nu jeg selv har siddet og keglet rundt med Graphviz i et par timer:

1) rankdir=LR har det *ikke* godt med rank=same - Enten virker det ikke, ellers er det meget uforudsigelige resultater du får ud af det. Så det er ikke en mulighed at bruge det til layouting, hvis du bruger rankdir=LR (som man normalt gerne vil ved f.eks. et NFA).

2) Det virker mest overskueligt at bruge usynlige edges til at tvinge ting til at ligge på samme niveau. Hvis man samtidigt benytter weight attributen, kan man tvinge ens usynlige edge til at blive lige. Du kan gøre en edge usynlig vha. style="invis". Eksempelvis a -> b [style="invis"]; .

3) ranksep er god til at begrænse størrelse af en graf, med en værdi af f.eks. .1 (ranksep=.1)

Martin Grunbaum

poizan42
Offline
Sv: Graphviz

Her er et lille fif hvis man vil have centreret en graf som er bredere end tekstbredden (dvs. går ind i margenerne). Et center environment virker i dette tilfælde ikke, og mere avancerede tricks er problematiske pga. hvordan dot2texi får tex til at se indholdet at dot2tex environmentet som rå data. Man kan løse det ved istedet at bruge en preamble og postamble i dot koden:

\begin{dot2tex}[codeonly]
digraph {
    d2tfigpreamble = "\par\noindent\makebox[\textwidth]{\begin{tikzpicture}[>=latex,line join=bevel,]";
    d2tfigpostamble = "\end{tikzpicture}}";

...

}
\end{dot2tex}

Hvis man også vil have skaleret grafen kan man ikke længere gøre dette med en attribut til environmentet pga. codeonly attributten. Istedet kan man gøre noget i stil med:

\begin{dot2tex}[codeonly]
digraph {
    d2tfigpreamble = "\par\noindent\makebox[\textwidth]{\begin{tikzpicture}[>=latex,line join=bevel,scale=0.5,transform shape]";
    d2tfigpostamble = "\end{tikzpicture}}";
...

}
\end{dot2tex}

Hvor scale=0.5 selvfølgelig kan ændres efter behov.

(Jeg undskylder for overløb i pre koden, men dot2tex kommer til at hænge hvis der er linjeskift i preamble/postamble strengene)

Ruben Nielsen
Offline
Sv: Graphviz

Mit unput:

\usepackage[dot, autosize, outputdir="dotgraphs/"]{dot2texi}
\usepackage{tikz}
\usetikzlibrary{shapes}

\begin{document}

\begin{dot2tex}
digraph {
rankdir = LR;
node [shape=circle];
start [color=white, shape=point];
q2 [shape=doublecircle];
start-> q1;
q1 -> q1 [label="a"];
q2 -> q2 [label="a"];
q1 -> q2 [label="b"];
q2 -> q1 [label="b"];
}
\end{dot2tex}

\end{document}

Men jeg får fejlen:

! Undefined control sequence.
\dottotexverbatimwrite ... \openout \verbatim@out
#1 \BeforeStream \let \do ...
l.73 d
igraph {
?
Process interrupted by user

Ingen ide om hvad jeg skal gøre... hjælp?

mikkeloscar
Offline
Sv: Graphviz

Du skal sørge for at have en mappe tilsvarende dit outputdir="dotgraphs/" og så skal du huske at give argumentet "--shell-escape" til din latex kommando, f.eks. "pdflatex --shell-escape dinfil.tex"

Det ville være nice hvis man kunne formatere sine kommentarer med markdown eller lign., det er godt nok rodet ;)