Gepostet von am 20. September 2008 in langgemachtes | 4 Kommentare

Inzwischen scheint sich die Visualisierung von Blogseiten und deren Beiträge bei mir zu einer Art Marotte entwickelt zu haben. Daher hat sich aus dem angekündigten „Tutorial light" doch etwas Größeres entwickelt.

Wie ich bereits im ersten Teil dieses Beitrags geschrieben habe, ist es möglich, mit Hilfe des GraphViz Site Map Generator seine Seiten bzw. Beiträge grafisch darstellen zu lassen. Voraussetzung war allerdings eine kleine Textdatei, aus der GraphViz die entsprechenden Daten ausliest.

Die Größe der Darstellung wird offensichtlich durch die generierte Grafik begrenzt, deren Grenze bei mehr als 50 Einträge in dieser Textdatei erreicht zu sein scheint. Die meisten Blogs verfügen jedoch über mehr als 50 Beiträge, so dass man sich in diesem Fall auf die letzten 50 Blogbeiträge beschränken muss.

Ein weiteres Problem ist die Verlinkung der einzelnen Beiträge untereinander, z.B. wenn via Ähnliche Artikel auf einen anderen Beitrag verwiesen wird.

Auf der Seite ashitani.jp/gv/ habe ich eine Lösung gefunden, die ebenfalls auf der Basis von GraphViz basiert. Auf dieser Seite werden übergroße Darstellungen sowie abnormale Notation ignoriert. Weitere Informationen zur Bedienung könnt Ihr unter dem Punkt Usage nachlesen.

GraphViz-Tutorial (node)

Ich möchte Euch anhand des dargestellten Diagramms erklären, wie Ihr bspw. Beiträge oder ähnliches visualisieren könnt. Dabei werde ich Schritt für Schritt dieses Diagramm erstellen und dabei die verwendeten Attribute und deren Eigenschaften genauer erläutern.

Die Eingabe auf dieser Seite erfolgt im linken Textfeld in der sogenannten DOT-Notation und die dazugehörige visuelle Ausgabe erhält man rechts daneben. Es sieht zunächst sehr kompliziert aus, aber wenn man einmal den Bogen raus hat, ist es nicht mehr so wild.

Texteingabe auf der Seite ashitani.jp

Grundsätzliches

Ich werde abschnittsweise vorgehen, d.h. ich fange beim Titel an und arbeite mich Ebene für Ebene nach unten. Auf diese Weise verliert Ihr nicht den Überblick und habt auch etwas Struktur in der Sache.

Natürlich werden sich im Laufe der Zeit viele Attribute und Eigenschaften wiederholen, so dass man sie eigentlich zusammenfassen könnte. Das Zusammenfassen macht sich zum Schluss am Besten, wenn sichergestellt ist, dass das Diagramm auch tatsächlich das ist, was man haben will.

Bevor es losgeht noch einige Hinweise.

GraphViz verfügt eigentlich über drei Objekte:

  • graph/digraph (ungerichteter/gerichteter Graph),
  • node (Knoten) und
  • edge (Kante)

mit entsprechenden Attributen und deren Eigenschaften.

Die Objekte graph/digraph brauchen auf der Seite ashitani.jp/gv/ nicht wie sonst üblich notiert werden.

Die verwendete Notation erfolgt in der Regel nach folgendem Schema:

Knoten1 [Knotenattribute="Eigenschaften"];
Knoten2 [Knotenattribute="Eigenschaften"];
...
Knoten1 Verknüpfungsoperator Knoten2;

bzw.

Kante [Kantenattribute="Eigenschaften"];.

Die Verbindung zweier Knoten, ohne den Einsatz weiterer Attribute, erfolgt durch diese beiden Verknüpfungsoperatoren:

  1. -- für einen ungerichteten Graphen oder
  2. -> für einen gerichteten Graphen.

Diese beiden Codebeispiele sollen das mal veranschaulichen.

Ungerichteter Graph: A--B; und gerichteter Graph: 1->2;. Die Grafik zeigt das Ergebnis.

ungerichteter und gerichteter Graph

Beide Vernüpfungsoperatoren können allerding nicht gleichzeitig in einer Anweisung eingesetzt werden, wie folgendes Beispiel zeigt: X--Y->Z;.

Um dennoch die Möglichkeit zu erhalten unterschiedliche Pfeiltypen zu nutzen, müssen die Pfeile entsprechend formatiert werden. Dazu später an anderer Stelle mehr.

Knoten und Kanten können aber auch in Gruppen, den sogenannten Clustern zusammengefasst werden. Die Notation erfolgt dabei nach folgendem Schema:

subgraph id {
   Clusterattribute="Eigenschaften";
   ...
   Knoten1 [Knotenattribute="Eigenschaften"];
   Knoten2 [Knotenattribute="Eigenschaften"];
   ...
   Kante [Kantenattribute="Eigenschaften"];
   Knoten1 Verknüpfungsoperator Knoten2;
   ...
}.

Im Grunde genommen wird der Cluster wie ein großer Knoten behandelt und auch so mit anderen Knoten verknüpft.

Das Semikolon am Ende der Zeile sollte gesetzt werden, auch wenn es nicht immer zwingend notwendig ist. Dadurch erspart man sich aber eine unnötige Suche nach Fehlern.

Jede Eingabe bzw. Veränderung des Codes im Textfeld dieser Seite ist immer mit der ENTER-Taste abzuschließen. Umlaute wie ä, ö, ü und ß sollten vermieden werden, da sonst das Diagramm nicht erstellt wird.

Außerdem sind Texte die Leerzeichen und folgende Satzzeichen: Komma, Punkt, Unterstrich, Semikolon, Bindestrich sowie spitze, eckige und geschweifte Klammern enthalten in Anführungszeichen "..." zu setzten.

Abschließend sei noch gesagt, dass ich Attribute und Eigenschaften sofort bei ihrem ersten Auftreten erläutern werde, im weiteren Verlauf jedoch nicht mehr darauf eingehe.

Okay jetzt aber genug geredet, dann fangen wir mal an.

Diagrammtitel der ersten Ebene

Als erstes geben wir unserem Diagramm einen Namen. Dazu geben wir folgendes ein:

  1. compound="true";
  2. remincross="true";
  3.  
  4. // Diagrammtitel der ersten Ebene
  5. "Kleines GraphViz Tutorial - Teil 1" [
  6.    shape="box",
       width="5.0",
       height="0.7",
       peripheries="1",
       fontcolor="0.6,0.9,0.8",
       fontsize="18",
       color="#A0522D",
       style="dashed,diagonals,filled",
       fillcolor="lavenderblush"
  7. ];
  8. // Hinweis
  9. "Liste unvollstaendig" [
  10.    shape="box",
       width="2.0",
       height="0.2",
       peripheries="1",
       fontcolor="black",
       fontsize="9",
       fontname="Courier",
       color="navy",
       style="filled",
       fillcolor="white"
  11. ];
  12.  

Die erste Ebene

Hinter dem Knotennamen "Kleines GraphViz Tutorial - Teil 1" folgen in eckigen Klammern die Knotenattribute. Diese bedeuten im einzelnen:

  1. Bindung: compound erlaubt Kanten zwischen Clustern, Werte true oder false
  2. Kantenkreuzung: remincross minimiert die Kreuzung von Kanten bei mehreren Clustern, Werte true oder false
  3. Knotenform: shape mit den Werten (box | polygon | ellipse | point | egg | triangle | diamond | trapezium | parallelogram | hexagon | octagon | doublecircle | tripleoctagon | invtriangle | invtrapezium)
  4. Größe: width und height mit Zahlenwerte in inch
  5. Anzahl der Rahmen: peripheries mit einem Zahlenwert
  6. Rahmenfarbe, Schriftfarbe und Füllfarbe: color, fontcolor und fillcolor mit Werten als Farbname, als HSB-Tripel mit Werten zwischen 0 und 1 oder als RGB-Tripel mit Hexadezimalwerten zwischen 00 und FF
  7. Schriftgröße: fontsize mit einem Zahlenwert
  8. Aussehen: style mit den Werten (solid | dashed | dotted | bold | diagonals | rounded)

Wie beim style-Attribut (Listingzeile 3) zu sehen ist, können Eigenschaften auch kombiniert werden. Wenn fillcolor nicht vorhanden ist und Ihr style="filled" gesetzt habt, dann wird dem Knoten die Farbe von color zugewiesen.

Zur Bindung und Kantenkreuzung findet Ihr am Ende des letzten Listings weitere Informationen. Ich wollte sie an dieser Stelle nur schon mal erwähnt haben.

Kante und Knoten der zweiten Ebene

Für die erste Ebene geben wir nachstehenden Code ein:

  1. // Kante erste Ebene - Knoten zweite Ebene
  2. edge [
  3.    color="slateblue",
       arrowhead="invodot",
       arrowtail="invodot",
       arrowsize="0.7"
  4. ];
  5.  
  6. // Knoten der zweiten Ebene
  7. node [
  8.    shape="box",
       width="15.0",
       peripheries="2",
       fontcolor="black",
       fontsize="12",
       color="powderblue",
       style="filled"
  9. ];
  10. "Kleines GraphViz Tutorial - Teil 1"--"Knoten-Attribute\nnode [attributes]";
  11.  

Die zweite Ebene

Um die logische Reihenfolge beizubehalten, habe ich zunächst mit der Kante begonnen. Sie wird durch edge eingeleitet und enthält neben der Kantenfarbe color noch diese zusätzlichen Kantenattribute:

  1. Kanten- bzw. Pfeilkopf: arrowhead mit den Werten (none | normal | dot | odot | inv | invdot | invodot)
  2. Kanten- bzw. Pfeilende: arrowtail mit den Werten (none | normal | dot | odot | inv | invdot | invodot)
  3. Kanten-/Pfeilgröße: arrowsize als skalierbarer Wert

Nachdem die Kante definiert wurde, wird nun ein zweiter Knoten gesetzt. Er wird durch node festgelegt und enthält alle dazugehörigen Attribute in eckigen Klammern. Anschließend wird der Knoten der ersten Ebene durch den Verknüpfungsoperator -- mit dem Knoten der zweiten Ebene "Knoten-Attribute\nnode" verknüpft, wie in Listingzeile 10 zu sehen ist.

Im zweiten Knotennamen ist zu erkennen, das mittels einer Escape-Sequenz \n ein Zeilenumbruch erzwungen wurde. Außerdem gibt es noch \l für eine linke sowie \r für eine rechte Textausrichtung.

Kante und Knoten der dritten Ebene

Für die dritte Ebene geben wir folgenden Code ein:

  1. // Kante zweite Ebene - Knoten dritte Ebene
  2. edge [
  3.    color="saddlebrown",
       arrowhead="dot",
       arrowtail="odot",
       arrowsize="0.7"
  4. ];
  5.  
  6. // Knoten der dritten Ebene
  7. node [
  8.    shape="ellipse",
       width="1.3",
       peripheries="2",
       fontcolor="black",
       color="lavender",
       style="filled"
  9. ];
  10. "Knoten-Attribute\nnode [attributes]"--"shape";
  11. "Knoten-Attribute\nnode [attributes]"--"peripheries";
  12. "Knoten-Attribute\nnode [attributes]"--"style";
  13. "Knoten-Attribute\nnode [attributes]"--"color";
  14. "Knoten-Attribute\nnode [attributes]"--"fillcolor";
  15. "Knoten-Attribute\nnode [attributes]"--"fontcolor";
  16. "Knoten-Attribute\nnode [attributes]"--"fontsize";
  17. "Knoten-Attribute\nnode [attributes]"--"fontname";
  18. "Knoten-Attribute\nnode [attributes]"--"width";
  19. "Knoten-Attribute\nnode [attributes]"--"height";
  20.  

Die dritte Ebene

Ich denke das ich hierzu nichts weiter erklären muss, da die Attribute oben alle schon mal aufgetaucht sind. Anschließend werden die Verknüpfungen zu den zehn Knoten der dritten Ebene hergestellt (Listingzeilen 10 bis 19).

Hinweis!
Attributnamen, die als Knotennamen verwendet werden, müssen zwingend in Anführungsstriche "..." gesetzt werden, da GraphViz sonst versucht, sie zu verarbeiten.

Kante und Knoten der vierten Ebene

Der Code der vierten Ebene ist etwas umfangreicher. Für Cluster1 lautet er folgendermaßen:

  1. // Cluster1 als Knoten der vierten Ebene
  2. // Gruppierung der Knoten zur Flaechendarstellung
  3. subgraph cluster1 {
  4.    fontsize="10";
       label="Die Flaechen" [
         fontcolor="darkgreen"
       ];
       style="filled";
       fillcolor="#FFF5E6";
  5.  
  6.    // Knoten zur Flaechendarstellung
  7.    node [
  8.      peripheries="1",
         fontcolor="#990000",
         fontsize="9",
         fontname="Courier",
         color="coral",
         style="filled",
         fillcolor="#F5FFF5"
  9.    ];
  10.    "box" [
  11.      shape="box"
  12.    ];
  13.    "polygon" [
  14.      shape="polygon",
         sides="9",
         skew="1.0",
         distortion="0.2"
  15.    ];
  16.    "ellipse" [
  17.      shape="ellipse"
  18.    ];
  19.    "point" [
  20.      shape="point",
         width="0.15"
  21.    ];
  22.    "egg" [
  23.      shape="egg"
  24.    ];
  25.    "triangle" [
  26.      shape="triangle"
  27.    ];
  28.    "diamond" [
  29.      shape="diamond"
  30.    ];
  31.    "trapezium" [
  32.      shape="trapezium"
  33.    ];
  34.    "parallelogram" [
  35.      shape="parallelogram"
  36.    ];
  37.    "hexagon" [
  38.      shape="hexagon"
  39.    ];
  40.    "octagon" [
  41.      shape="octagon"
  42.    ];
  43.    "doublecircle" [
  44.      shape="doublecircle",
         peripheries="2"
  45.    ];
  46.    "tripleoctagon" [
  47.      shape="tripleoctagon",
         peripheries="3"
  48.    ];
  49.    "invtriangle" [
  50.      shape="invtriangle"
  51.    ];
  52.    "invtrapezium" [
  53.      shape="invtrapezium"
  54.    ];
  55.  
  56.    edge [
  57.      color="royalblue",
         arrowhead="none",
         arrowtail="none"
  58.    ];
  59.  
  60.    "box"--"polygon"--"ellipse"--"point"--"egg"--"triangle"--
       "diamond"--"trapezium"--"parallelogram"--"hexagon"--
       "octagon"--"doublecircle"--"tripleoctagon"--"invtriangle"--
       "invtrapezium";
  61. }
  62.  

Die vierte Ebene – Cluster1

Cluster werden, wie in Listingzeile 3 zu sehen ist, mit subgraph id {...} eingeleitet, wobei die id dem Clusternamen entspricht. Die im Cluster befindlichen Objekte, wie Knoten und Kanten, stehen innerhalb geschweiften Klammern. Vor Abschluss des Clusters werden noch die 15 Knoten angelegt.

Nun zu den neu hinzugekommenen Attributen.

  1. Beschriftung: label mit einen Namen
  2. Anzahl der Seiten: sides mit einem Zahlenwert (nur bei shape="polygon")
  3. Schräge: skew mit Werte zwischen -1.0 und 1.0 (nur bei shape="polygon")
  4. Verzerrung: distortion mit einem Zahlenwert (nur bei shape="polygon")

Hier der Code für Cluster2:

  1. // Cluster2 als Knoten der vierten Ebene
  2. // Gruppierung der Knoten zum Aussehen
  3. subgraph cluster2 {
  4.    fontsize="10";
  5.    label="Das Aussehen" [
  6.      fontcolor="darkgreen"
  7.    ];
  8.    style="filled";
  9.    fillcolor="#FFF5E6";
  10.  
  11.    // Knoten zum Aussehen
  12.    node [
  13.      shape="box",
         peripheries="1",
         fontcolor="#990000",
         fontsize="9",
         fontname="Courier",
         color="coral",
         fillcolor="#F5FFF5"
  14.    ];
  15.    "solid" [
  16.      style="solid,filled"
  17.    ];
  18.    "dashed" [
  19.      style="dashed,filled"
  20.    ];
  21.    "dotted" [
  22.      style="dotted,filled"
  23.    ];
  24.    "bold" [
  25.      style="bold,filled"
  26.    ];
  27.    "diagonals" [
  28.      style="diagonals,filled"
  29.    ];
  30.    "rounded" [
  31.      style="rounded,filled"
  32.    ];
  33.  
  34.    edge [
  35.      color="royalblue",
         arrowhead="none",
         arrowtail="none"
  36.    ];
  37.  
  38.    "solid"--"dashed"--"dotted"--"bold"--"diagonals"--
       "rounded";
  39. }
  40.  

Die vierte Ebene – Cluster2

Weitere Erklärungen erübrigen sich, da ich bereits beim ersten Cluster alles wichtige genannt habe. Vor der schließenden geschweiften Klammer legen wir noch die sechs Knoten an.

Der Vollständigkeit halber hier noch der Code für Cluster3:

  1. // Cluster3 als Knoten der vierten Ebene
  2. // Gruppierung der Knoten zur Schriftart
  3. subgraph cluster3 {
  4.    fontsize="10";
  5.    label="Die Schriftart" [
  6.      fontcolor="darkgreen"
  7.    ];
  8.    style="filled";
  9.    fillcolor="#FFF5E6";
  10.  
  11.    // Knoten zur Schriftart
  12.    node [
  13.      shape="box",
         peripheries="1",
         fontcolor="#990000",
         fontsize="9",
         color="coral",
         style="filled",
         fillcolor="#F5FFF5"
  14.    ];
  15.    "Standardschrift";
  16.    "Times" [
  17.      fontname="Times"
  18.    ];
  19.    "Helvetica" [
  20.      fontname="Helvetica"
  21.    ];
  22.    "Courier" [
  23.      fontname="Courier"
  24.    ];
  25.    "Symbol" [
  26.      fontname="Symbol"
  27.    ];
  28.  
  29.    edge [
  30.      color="royalblue",
         arrowhead="none",
         arrowtail="none"
  31.    ];
  32.  
  33.    "Standardschrift"--"Times"--"Helvetica"--"Courier"--
       "Symbol";
  34. }
  35.  

Die vierte Ebene – Cluster3

Die fünf Knoten am Ende bilden den Abschluss des dritten Cluster.

Hinweis!
Ich habe in den Listings für Cluster1 in Zeile 60, für Cluster2 in Zeile 38 sowie für Cluster3 in Zeile 33 aufgrund der Länge Zeilenumbrüche eingefügt. Diese Zeileneinträge müssen komplett hintereinander geschrieben werden!

Abschließend folgt noch der restliche Code:

  1. // Kante dritte Ebene - Cluster1, 2, 3 und Knoten der vierten Ebene
  2. edge [
  3.    color="darkseagreen",
       arrowhead="none",
       arrowtail="inv",
       arrowsize="0.7"
  4. ];
  5.  
  6. "shape"--"box" [
  7.    lhead="cluster1"
  8. ];
  9. "style"--"solid" [
  10.    lhead="cluster2"
  11. ];
  12. "fontname"--"Standardschrift" [
  13.    lhead="cluster3"
  14. ];
  15.  
  16. // Knoten der vierten Ebene
  17. node [
  18.    shape="box",
       peripheries="1",
       fontcolor="#990000",
       fontsize="9",
       fontname="Courier",
       color="black",
       style="filled",
       fillcolor="#FFF5E6"
  19. ];
  20. "peripheries"--"Zahlenwert, z.B. 5";
  21. "color"--"Farbname, RGB- oder HSB-Tripel\nroyalblue, #FF0000 oder 0.6,0.9,0.8";
  22. "fillcolor"--"Farbname, RGB- oder HSB-Tripel\nroyalblue, #FF0000 oder 0.6,0.9,0.8";
  23. "fontcolor"--"Farbname, RGB- oder HSB-Tripel\nroyalblue, #FF0000 oder 0.6,0.9,0.8";
  24. "fontsize"--"Zahlenwert, z.B. 5";
  25. "width"--"Zahlenwert in inch, z.B. 2.5";
  26. "height"--"Zahlenwert in inch, z.B. 2.5";
  27.  

Die vierte Ebene

Die zwei neuen Attribute lauten.

  1. Kantenansatz: lhead Name des Clusters der den Kopf der Kante verwendet
  2. Kantenansatz: ltail Name des Clusters der das Ende der Kante verwendet

In Verbindung mit dem Befehl compound="true";, in der Grafik rechts, erfolgt der Ansatz direkt am Rand des Clusters. Ist dieser auf false gesetzt, links in der Grafik, erfolgt der Ansatz in diesem Fall am Knoten "box", am Knoten "solid" bzw. am Knoten "Standardschrift".

Der Befehl remincross="true"; verhindert bei Verwenden mehrerer Cluster eine unnötige Überkreuzung von Kanten.

compound false und compound true

Damit Ihr nicht alles mühsam abtippen zu müssen, stelle ich Euch mal die dazugehörige Textdatei graphviz_tutorial_node zur Verfügung.

Eine Einführung in die DOT-Notation findet Ihr in diesem PDF-Dokument dot_guide. Auch jene Kanten-Attribute, die ich Euch unterschlagen habe. Außerdem erhaltet Ihr auf der Seite von GraphViz viele weitere Informationen.

Der zweite Teil wird sich dann mit den Kanten-Attributen (edge attributes) befassen. Bis dahin viel Spaß beim experimentieren.

Weiterführende Links:

Artikel getaggt mit ,

Diesen Artikel weiterempfehlen:
Autorfoto
Oliver Konow
Ich bin 51 und beruflich dem Hochgeschwindigkeitsverkehr verfallen. Die Fotografie ist mein Hobby und Reisen meine Leidenschaft. Darüber hinaus interessieren mich Fraktale sowie die Astronomie.

4 Kommentare

  1. 13. Januar 2010

    Habe Ihren Blog durch Eingabe der Schlagworte „Graphviz compound" gefunden und dann entdeckt, dass sie auch aus Neubrandenburg sind. Danke für dieses wunderbare Tutorial! Es war mir sehr hilfreich. Grüße, Jensen

  2. 13. Januar 2010

    Schön das ich einen „Landsmann" helfen konnte. Grüße zurück!

  3. 19. Juli 2011

    danke für das tut. endlich habe ich da was gefunden

  4. 20. Juli 2011

    Keine Ursache. Ich helfe gern und Grüße nach Leipzig.

Kommentar absenden

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.