Graphs and Graphviz DOT
In this tutorial you build a directed graph with the graph DSL, style its nodes and edges, and write it as Graphviz DOT source text ready for rendering.
Step 1: Add the dependencies
You need markup-graph (the graph model and DSL) and markup-dot-writer (the DOT writer):
kotlin {
sourceSets {
commonMain.dependencies {
implementation("org.markup-poet:markup-graph:0.2.0")
implementation("org.markup-poet:markup-dot-writer:0.2.0")
}
}
}
Step 2: Build your first digraph
Create a directed graph with two nodes and one edge:
import org.markup.poet.dsl.graph.digraph
import org.markup.poet.dsl.write.dot.toDot
val g = digraph("Pipeline") {
node("parse") { shape = "box" }
node("write") { shape = "box" }
edge("parse", "write") { label = "model" }
}
println(g.toDot())
You should see:
digraph Pipeline {
parse [shape=box];
write [shape=box];
parse -> write [label=model];
}
digraph builds a directed graph; graph builds an undirected one (edges are written with -- instead of →).
Step 3: Style nodes and edges
Nodes have typed shape, color, and label properties; edges have style, color, and label:
val g = digraph("StyledGraph") {
node("A") {
shape = "box"
color = "red"
}
node("B") {
shape = "ellipse"
color = "blue"
}
edge("A", "B") {
style = "dashed"
color = "black"
}
edge("B", "A") {
style = "bold"
color = "orange"
}
}
toDot() produces:
digraph StyledGraph {
A [shape=box, color=red];
B [shape=ellipse, color=blue];
A -> B [style=dashed, color=black];
B -> A [style=bold, color=orange];
}
Step 4: Set arbitrary attributes
Beyond the typed properties, attr(name, value) passes any attribute through at graph, node, and edge level, so the full DOT attribute vocabulary is available:
val g = digraph("Pipeline") {
attr("rankdir", "LR")
node("A") {
shape = "box"
attr("penwidth", "2")
}
edge("A", "B") {
attr("weight", "3")
}
}
digraph Pipeline {
rankdir=LR;
A [shape=box, penwidth=2];
A -> B [weight=3];
}
Note that the edge references node B without a matching node("B") declaration. That is allowed: edges may reference undeclared ids, which become implicit nodes, just as in DOT itself.
Step 5: Render with Graphviz
Write the output to a file and run Graphviz:
dot -Tsvg pipeline.dot -o pipeline.svg
Next steps
-
Check graphs for cycles and sort them topologically: Analyze DAGs
-
Look up how the graph model maps to DOT syntax: DOT mapping