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.
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.
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) undedge
(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:
--
für einen ungerichteten Graphen oder->
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.
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:
compound="true";
remincross="true";
// Diagrammtitel der ersten Ebene
"Kleines GraphViz Tutorial - Teil 1" [
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"];
// Hinweis
"Liste unvollstaendig" [
shape="box",
width="2.0",
height="0.2",
peripheries="1",
fontcolor="black",
fontsize="9",
fontname="Courier",
color="navy",
style="filled",
fillcolor="white"];
Die erste Ebene
Hinter dem Knotennamen "Kleines GraphViz Tutorial - Teil 1"
folgen in eckigen Klammern die Knotenattribute. Diese bedeuten im einzelnen:
- Bindung:
compound
erlaubt Kanten zwischen Clustern, Wertetrue
oderfalse
- Kantenkreuzung:
remincross
minimiert die Kreuzung von Kanten bei mehreren Clustern, Wertetrue
oderfalse
- Knotenform:
shape
mit den Werten (box
|polygon
|ellipse
|point
|egg
|triangle
|diamond
|trapezium
|parallelogram
|hexagon
|octagon
|doublecircle
|tripleoctagon
|invtriangle
|invtrapezium
) - Größe:
width
undheight
mit Zahlenwerte in inch - Anzahl der Rahmen:
peripheries
mit einem Zahlenwert - Rahmenfarbe, Schriftfarbe und Füllfarbe:
color
,fontcolor
undfillcolor
mit Werten als Farbname, als HSB-Tripel mit Werten zwischen0
und1
oder als RGB-Tripel mit Hexadezimalwerten zwischen00
undFF
- Schriftgröße:
fontsize
mit einem Zahlenwert - 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:
// Kante erste Ebene - Knoten zweite Ebene
edge [
color="slateblue",
arrowhead="invodot",
arrowtail="invodot",
arrowsize="0.7"];
// Knoten der zweiten Ebene
node [
shape="box",
width="15.0",
peripheries="2",
fontcolor="black",
fontsize="12",
color="powderblue",
style="filled"];
"Kleines GraphViz Tutorial - Teil 1"--"Knoten-Attribute\nnode [attributes]";
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:
- Kanten- bzw. Pfeilkopf:
arrowhead
mit den Werten (none
|normal
|dot
|odot
|inv
|invdot
|invodot
) - Kanten- bzw. Pfeilende:
arrowtail
mit den Werten (none
|normal
|dot
|odot
|inv
|invdot
|invodot
) - 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:
// Kante zweite Ebene - Knoten dritte Ebene
edge [
color="saddlebrown",
arrowhead="dot",
arrowtail="odot",
arrowsize="0.7"];
// Knoten der dritten Ebene
node [
shape="ellipse",
width="1.3",
peripheries="2",
fontcolor="black",
color="lavender",
style="filled"];
"Knoten-Attribute\nnode [attributes]"--"shape";
"Knoten-Attribute\nnode [attributes]"--"peripheries";
"Knoten-Attribute\nnode [attributes]"--"style";
"Knoten-Attribute\nnode [attributes]"--"color";
"Knoten-Attribute\nnode [attributes]"--"fillcolor";
"Knoten-Attribute\nnode [attributes]"--"fontcolor";
"Knoten-Attribute\nnode [attributes]"--"fontsize";
"Knoten-Attribute\nnode [attributes]"--"fontname";
"Knoten-Attribute\nnode [attributes]"--"width";
"Knoten-Attribute\nnode [attributes]"--"height";
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:
// Cluster1 als Knoten der vierten Ebene
// Gruppierung der Knoten zur Flaechendarstellung
subgraph cluster1 {
fontsize="10";
label="Die Flaechen" [
fontcolor="darkgreen"
];
style="filled";
fillcolor="#FFF5E6";// Knoten zur Flaechendarstellung
node [
peripheries="1",
fontcolor="#990000",
fontsize="9",
fontname="Courier",
color="coral",
style="filled",
fillcolor="#F5FFF5"];
"box" [
shape="box"
];
"polygon" [
shape="polygon",
sides="9",
skew="1.0",
distortion="0.2"];
"ellipse" [
shape="ellipse"
];
"point" [
shape="point",
width="0.15"];
"egg" [
shape="egg"
];
"triangle" [
shape="triangle"
];
"diamond" [
shape="diamond"
];
"trapezium" [
shape="trapezium"
];
"parallelogram" [
shape="parallelogram"
];
"hexagon" [
shape="hexagon"
];
"octagon" [
shape="octagon"
];
"doublecircle" [
shape="doublecircle",
peripheries="2"];
"tripleoctagon" [
shape="tripleoctagon",
peripheries="3"];
"invtriangle" [
shape="invtriangle"
];
"invtrapezium" [
shape="invtrapezium"
];
edge [
color="royalblue",
arrowhead="none",
arrowtail="none"];
"box"--"polygon"--"ellipse"--"point"--"egg"--"triangle"--
"diamond"--"trapezium"--"parallelogram"--"hexagon"--
"octagon"--"doublecircle"--"tripleoctagon"--"invtriangle"--
"invtrapezium";}
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.
- Beschriftung:
label
mit einen Namen - Anzahl der Seiten:
sides
mit einem Zahlenwert (nur beishape="polygon"
) - Schräge:
skew
mit Werte zwischen -1.0 und 1.0 (nur beishape="polygon"
) - Verzerrung:
distortion
mit einem Zahlenwert (nur beishape="polygon"
)
Hier der Code für Cluster2:
// Cluster2 als Knoten der vierten Ebene
// Gruppierung der Knoten zum Aussehen
subgraph cluster2 {
fontsize="10";
label="Das Aussehen" [
fontcolor="darkgreen"
];
style="filled";
fillcolor="#FFF5E6";
// Knoten zum Aussehen
node [
shape="box",
peripheries="1",
fontcolor="#990000",
fontsize="9",
fontname="Courier",
color="coral",
fillcolor="#F5FFF5"];
"solid" [
style="solid,filled"
];
"dashed" [
style="dashed,filled"
];
"dotted" [
style="dotted,filled"
];
"bold" [
style="bold,filled"
];
"diagonals" [
style="diagonals,filled"
];
"rounded" [
style="rounded,filled"
];
edge [
color="royalblue",
arrowhead="none",
arrowtail="none"];
"solid"--"dashed"--"dotted"--"bold"--"diagonals"--
"rounded";}
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:
// Cluster3 als Knoten der vierten Ebene
// Gruppierung der Knoten zur Schriftart
subgraph cluster3 {
fontsize="10";
label="Die Schriftart" [
fontcolor="darkgreen"
];
style="filled";
fillcolor="#FFF5E6";
// Knoten zur Schriftart
node [
shape="box",
peripheries="1",
fontcolor="#990000",
fontsize="9",
color="coral",
style="filled",
fillcolor="#F5FFF5"];
"Standardschrift";
"Times" [
fontname="Times"
];
"Helvetica" [
fontname="Helvetica"
];
"Courier" [
fontname="Courier"
];
"Symbol" [
fontname="Symbol"
];
edge [
color="royalblue",
arrowhead="none",
arrowtail="none"];
"Standardschrift"--"Times"--"Helvetica"--"Courier"--
"Symbol";}
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:
// Kante dritte Ebene - Cluster1, 2, 3 und Knoten der vierten Ebene
edge [
color="darkseagreen",
arrowhead="none",
arrowtail="inv",
arrowsize="0.7"];
"shape"--"box" [
lhead="cluster1"
];
"style"--"solid" [
lhead="cluster2"
];
"fontname"--"Standardschrift" [
lhead="cluster3"
];
// Knoten der vierten Ebene
node [
shape="box",
peripheries="1",
fontcolor="#990000",
fontsize="9",
fontname="Courier",
color="black",
style="filled",
fillcolor="#FFF5E6"];
"peripheries"--"Zahlenwert, z.B. 5";
"color"--"Farbname, RGB- oder HSB-Tripel\nroyalblue, #FF0000 oder 0.6,0.9,0.8";
"fillcolor"--"Farbname, RGB- oder HSB-Tripel\nroyalblue, #FF0000 oder 0.6,0.9,0.8";
"fontcolor"--"Farbname, RGB- oder HSB-Tripel\nroyalblue, #FF0000 oder 0.6,0.9,0.8";
"fontsize"--"Zahlenwert, z.B. 5";
"width"--"Zahlenwert in inch, z.B. 2.5";
"height"--"Zahlenwert in inch, z.B. 2.5";
Die vierte Ebene
Die zwei neuen Attribute lauten.
- Kantenansatz:
lhead
Name des Clusters der den Kopf der Kante verwendet - 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.
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:
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
Schön das ich einen “Landsmann” helfen konnte. Grüße zurück!
danke für das tut. endlich habe ich da was gefunden
Keine Ursache. Ich helfe gern und Grüße nach Leipzig.