Render graphs directly in your posts with [dot]
your DOT source here[/dot]`.
When you are posting something here at the forum and want to show a graph that is generated by some DOT source code; wouldn’t it be great if you could just generate the graph here directly from your DOT source code instead of generating it offline and copy-and-paste it into your post? What I mean is being able to embed stuff like:
[dot verbose=true delay=1000 duration=2000 width=400]
digraph {
node [style="filled"]
a [fillcolor="#d62728"]
b [fillcolor="#1f77b4"]
a -> b
}
[/dot]
[dot delay=0]
digraph {
node [style="filled"]
a [fillcolor="#d62728" shape="box"]
b [fillcolor="#1f77b4" shape="parallelogram"]
c [fillcolor="#2ca02c"]
a -> b
a -> c
}
[/dot]
Well…
Now you can!
The graph above was rendered just that. This article is a description of how you can do it yourself. It assumes you’re already familiar with the DOT language. We’re going to start with the very simple basic uses cases and move on to more advanced features.
Meet the [dot] tag
Static graphs
Write:
[dot]digraph {a -> b}[/dot]
and you get:
[dot]digraph {a → b}[/dot]
Not only that; you can also do…
Animated transitions between graphs
Write:
[dot]digraph {a -> b}[/dot]
[dot]digraph {a -> b; a -> c}[/dot]
[dot]digraph {a -> b; a -> c; b -> c}[/dot]
and you will have:
[dot]digraph {a → b}[/dot]
[dot]digraph {a → b; a → c}[/dot]
[dot]digraph {a → b; a → c; b → c}[/dot]
Click the play button to the left of the graph to play the animation once again or the repeat button to play it continuously.
Inlined graphs
You can inline one or more graphs in the text with:
Here is a graph: [dot] digraph {rankdir=LR size=1.5 Hello -> "World!"} [/dot] and here is another one: [dot] digraph {rankdir=LR size=1.5 Good -> "Night!"} [/dot]. Those were the graphs.
which gets you:
Here is a graph: [dot] digraph {rankdir=LR size=1.5 Hello → “World!”} [/dot] and here is another one: [dot] digraph {rankdir=LR size=1.5 Good → “Night!”} [/dot]. Those were the graphs.
Don’t worry about the vertical alignment; you can fix that, but we’re not ready for it yet, so read on.
Block graphs
For larger graphs it’s more convenient to write them as a separate block:
This is the cluster example from the [Graphviz Gallery]
(https://graphviz.gitlab.io/_pages/Gallery/directed/cluster.html):
[dot]
digraph G {
subgraph cluster_0 {
style=filled;
color=lightgrey;
node [style=filled,color=white];
a0 -> a1 -> a2 -> a3;
label = "process #1";
}
subgraph cluster_1 {
node [style=filled];
b0 -> b1 -> b2 -> b3;
label = "process #2";
color=blue
}
start -> a0;
start -> b0;
a1 -> b3;
b2 -> a3;
a3 -> a0;
a3 -> end;
b3 -> end;
start [shape=Mdiamond];
end [shape=Msquare];
}
[/dot]
which renders:
This is the cluster example from the Graphviz Gallery:
[dot]
digraph G {
subgraph cluster_0 {
style=filled;
color=lightgrey;
node [style=filled,color=white];
a0 -> a1 -> a2 -> a3;
label = "process #1";
}
subgraph cluster_1 {
node [style=filled];
b0 -> b1 -> b2 -> b3;
label = "process #2";
color=blue
}
start -> a0;
start -> b0;
a1 -> b3;
b2 -> a3;
a3 -> a0;
a3 -> end;
b3 -> end;
start [shape=Mdiamond];
end [shape=Msquare];
}
[/dot]
Preventing forum formatting to interfere with DOT source code
Unfortunately the forum formatting rules may interfere with certain legal DOT source code.
This does not work
The text:
[dot]digraph {a -> b /*comment*/}[/dot]
will after formatting become:
[dot]digraph {a → b /my comment/}[/dot]
which will not generate any graph.
Do this instead
To avoid this, place the DOT source code within backticks (`
) or [code]
tags like this:
[dot]`digraph {a -> b /*comment*/}`[/dot]
or
[dot][code]digraph {a -> b /*comment*/}[/code][/dot]
or
[dot]
```
digraph {
a ->b /*comment*/
}
```
[/dot]
Selecting layout engine
The engine option
You can select which layout engine to use with the engine
option:
Layout engine in a static graph
[dot engine=circo] digraph {a -> b; a -> c; a -> d} [/dot]
[dot engine=circo] digraph {a → b; a → c; a → d} [/dot]
Showing the difference between layout engines as an animation
You can even have different layout engines for each graph in an animated transition sequence:
[dot engine=circo] digraph {label=circo; a -> b -> c -> d; c -> e} [/dot]
[dot engine=dot] digraph {label=dot; a -> b -> c -> d; c -> e} [/dot]
[dot engine=fdp] digraph {label=fdp; a -> b -> c -> d; c -> e} [/dot]
[dot engine=neato] digraph {label=neato; a -> b -> c -> d; c -> e} [/dot]
[dot engine=osage] digraph {label=osage; a -> b -> c -> d; c -> e} [/dot]
[dot engine=patchwork] digraph {label=patchwork; a -> b -> c -> d; c -> e} [/dot]
[dot engine=twopi] digraph {label=twopi; a -> b -> c -> d; c -> e} [/dot]
[dot engine=circo] digraph {label=circo; a → b → c → d; c → e} [/dot]
[dot engine=dot] digraph {label=dot; a → b → c → d; c → e} [/dot]
[dot engine=fdp] digraph {label=fdp; a → b → c → d; c → e} [/dot]
[dot engine=neato] digraph {label=neato; a → b → c → d; c → e} [/dot]
[dot engine=osage] digraph {label=osage; a → b → c → d; c → e} [/dot]
[dot engine=patchwork] digraph {label=patchwork; a → b → c → d; c → e} [/dot]
[dot engine=twopi] digraph {label=twopi; a → b → c → d; c → e} [/dot]
Automatically show the DOT source code
The verbose option
Inline verbose
If you are a fan of Graphviz and the DOT language, you might want to show the DOT source code that was used to generate the graph. You can do that automatically by adding the verbose
option:
[dot verbose=true] digraph {rankdir=LR Alice -> Bob} [/dot]
This gives you:
[dot verbose=true] digraph {rankdir=LR Alice → Bob} [/dot]
Block verbose
In order the preserve whitespace, such as indentation and multiple blank lines, you need to put the dot source code within a ```
or [code]
block:
[dot verbose=true]
```
digraph {
rankdir=LR
Alice -> Bob
}
```
[/dot]
will give:
[dot verbose=true]
digraph {
rankdir=LR
Alice -> Bob
}
[/dot]
This is equivalent:
[dot verbose=true]
[code]
digraph {
rankdir=LR
Alice -> Bob
}
[/code]
[/dot]
which gives:
[dot verbose=true]
digraph {
rankdir=LR
Alice -> Bob
}
[/dot]
Styling
The border option
The border
option allows you to put a CSS border around your graph:
[dot border="3px dotted red"] digraph {CSS -> Style} [/dot]
[dot border=“3px dotted red”] digraph {CSS → Style} [/dot]
The style option
In fact, through the style
option, you can use any CSS style:
[dot style="margin: 50px; padding: 100px; border: 5px solid royalblue; border-radius:50px; background-color: mediumseagreen"]
digraph {CSS -> Style}
[/dot]
[dot style=“margin: 50px; padding: 100px; border: 5px solid royalblue; border-radius:50px; background-color: mediumseagreen”]
digraph {CSS → Style}
[/dot]
Vertically aligning inlined graphs
Remember that I said above that you could fix the vertical alignment for inlined graphs? Here is how:
Here is a graph: [dot style="vertical-align: middle"] digraph {rankdir=LR size=1.5 Hello -> "World!"} [/dot] and here is another one: [dot style="vertical-align: middle"] digraph {rankdir=LR size=1.5 Good -> "Night!"} [/dot]. Those were the graphs.
which gives you
Here is a graph: [dot style=“vertical-align: middle”] digraph {rankdir=LR size=1.5 Hello → “World!”} [/dot] and here is another one: [dot style=“vertical-align: middle”] digraph {rankdir=LR size=1.5 Good → “Night!”} [/dot]. Those were the graphs.
Interactivity
Pan and zoom
You may already have noticed that you can pan and zoom all the graphs above. While this is very useful for large graphs, it doesn’t make sense for small ones and can be just annoying when you try to scroll through the page with the mouse wheel. Therefore it’s possible to disable zooming.
The zoom option
Zoom enabled (default)
[dot border="1px solid red"] digraph {a -> b} [/dot]
[dot border=“1px solid red”] digraph {a → b} [/dot]
Zoom disabled
[dot border="1px solid blue" zoom=false]
digraph {a -> b}
[/dot]
[dot border=“1px solid blue” zoom=false]
digraph {a → b}
[/dot]
Limiting the zooming extent
It may not be sensible to zoom in or out too much or pan to far away. Therefore it’s possible to limit this.
The zoomScaleExtent option
Zoom scale extent (0.5, 2)
Limits zooming to a factor of two up or down.
[dot zoomScaleExtent=(0.5,2) border="1px solid green"]
digraph {a -> b}
[/dot]
[dot zoomScaleExtent=(0.5,2) border=“1px solid green” ]
digraph {a → b}
[/dot]
The zoomTranslateExtent option
Zoom translate extent ((-159,-402),(213,294))
The translate extent restricts panning. Knowing that this graph is 62 x 116 points and has an initial translation of (-4, 112), the panning can be restricted so that at least 31 x 58 points, i.e. the center of the graph is always visible in an area 3 times the width and height of the original graph:
[dot border="1px solid black" width=248 height=464 zoomTranslateExtent=((-159,-402),(213,294)) zoomScaleExtent=(1,1)]
digraph {bgcolor=royalblue a -> b}
[/dot]
[dot border=“1px solid black” width=248 height=464 zoomTranslateExtent=((-159,-402),(213,294)) zoomScaleExtent=(1,1)]
digraph {bgcolor=royalblue a → b}
[/dot]
Reader animation controls
Default behavior of an animation
An animation consists of a series of graphs and transitions between them. Playing an animation means to show a sequence of transitions between the graphs. The default behavior is to play an animation until the last graph in the sequence and then stop.
Animation control buttons
To the left of each animated graph, there are two buttons: the Play/Pause button and the Repeat/Stop button which lets the reader control the animations.
If the reader presses the Pause button during an animation, the sequence is paused at the next graph in the sequence. When the reader presses the Play button the animation is resumed from the current graph. If the reader presses the Repeat button, the animation will play to the last graph and then start over with the first graph in a endless loop. If the reader then presses the Stop button, the animation will play to the last graph in the sequence and then stop:
[dot] digraph {a -> b}[/dot]
[dot] digraph {a -> b; a -> c}[/dot]
[dot] digraph {a -> c a -> b}[/dot]
[dot] digraph {a → b}[/dot]
[dot] digraph {a → b; a → c}[/dot]
[dot] digraph {a → c a → b}[/dot]
Initial state of the animation control buttons
In some cases, it might be desirable to change the default behavior of an animation. This can be done by changing the initial state of the animation controls with the play
and repeat
options.
The play option
Start in paused state
[dot play=false] digraph {a -> b}[/dot]
[dot] digraph {a -> b; a -> c}[/dot]
[dot] digraph {c -> a; c -> b }[/dot]
[dot play=false] digraph {a → b}[/dot]
[dot] digraph {a → b; a → c}[/dot]
[dot] digraph {c → a; c → b }[/dot]
The repeat option
Start in repeat state
[dot repeat=true] digraph {a -> b}[/dot]
[dot] digraph {a -> b; a -> c}[/dot]
[dot] digraph {a -> c a -> b}[/dot]
[dot repeat=true] digraph {edge [style=invis]; b → c; b → a}[/dot]
[dot] digraph {edge [style=invis]; a → b; a → c}[/dot]
[dot] digraph {edge [style=invis]; c → a; c → b }[/dot]
Note: Avoid this setting except in very special cases. Never-ending animations can be really annoying to readers, even though they have the possibility to stop them.
Animation controls in the editor preview
In the editor preview, the animations are paused by default and have to be started manually regardless what the play
option is set to. Every time an edit is made the state returns to paused and the first graph in the sequence is shown.
Animated transition timing
The timing of animated transitions can be controlled by the delay
, duration
and ease
options:
Default timing
The default timing is to have a 500 milliseconds pause before starting a transition and a 1500 milliseconds duration and use a cubic easing function:
[dot repeat=true] digraph {edge [style=invis]; b -> c; b -> a}[/dot]
[dot] digraph {edge [style=invis]; a -> b; a -> c}[/dot]
[dot] digraph {edge [style=invis]; c -> a; c -> b }[/dot]
[dot repeat=true] digraph {edge [style=invis]; b → c; b → a}[/dot]
[dot] digraph {edge [style=invis]; a → b; a → c}[/dot]
[dot] digraph {edge [style=invis]; c → a; c → b }[/dot]
The duration and delay options
Slow animation with longer pause
[dot repeat=true delay=1000 duration=3000] digraph {edge [style=invis]; b -> c; b -> a}[/dot]
[dot] digraph {edge [style=invis]; a -> b; a -> c}[/dot]
[dot] digraph {edge [style=invis]; c -> a; c -> b }[/dot]
[dot repeat=true delay=1000 duration=3000] digraph {edge [style=invis]; b → c; b → a}[/dot]
[dot] digraph {edge [style=invis]; a → b; a → c}[/dot]
[dot] digraph {edge [style=invis]; c → a; c → b }[/dot]
Fast animation without pause
[dot repeat=true delay=0 duration=700] digraph {edge [style=invis]; b -> c; b -> a}[/dot]
[dot] digraph {edge [style=invis]; a -> b; a -> c}[/dot]
[dot] digraph {edge [style=invis]; c -> a; c -> b }[/dot]
[dot repeat=true delay=0 duration=700] digraph {edge [style=invis]; b → c; b → a}[/dot]
[dot] digraph {edge [style=invis]; a → b; a → c}[/dot]
[dot] digraph {edge [style=invis]; c → a; c → b }[/dot]
The ease option
Fast animation with linear easing
[dot repeat=true delay=0 duration=700 ease=linear] digraph {edge [style=invis]; b -> c; b -> a}[/dot]
[dot] digraph {edge [style=invis]; a -> b; a -> c}[/dot]
[dot] digraph {edge [style=invis]; c -> a; c -> b }[/dot]
[dot repeat=true delay=0 duration=700 ease=linear] digraph {edge [style=invis]; b → c; b → a}[/dot]
[dot] digraph {edge [style=invis]; a → b; a → c}[/dot]
[dot] digraph {edge [style=invis]; c → a; c → b }[/dot]
Advanced transition options
The are a number of other, more advanced transition options. See the d3-graphviz options section in the options reference.
Resizing and scaling the graph
Sometimes you want a smaller or larger area than the actual size of the default generated SVG and you may also want to scale or fit the graph into that area. Below are some examples on how to do that. The different options are not independent; to fully understand how they operate, please see Controlling SVG Size and Graph Size.
Original sized SVG
Original sized SVG with normal sized graph
[dot border="1px solid black"]
digraph {a -> b}
[/dot]
[dot border=“1px solid black”]
digraph {a → b}
[/dot]
Original sized SVG with downscaled graph
[dot border="1px solid black" scale=0.5]
digraph {a -> b}
[/dot]
[dot border=“1px solid black” scale=0.5]
digraph {a → b}
[/dot]
Original sized SVG with upscaled graph
[dot border="1px solid black" scale=2]
digraph {a -> b}
[/dot]
[dot border=“1px solid black” scale=2]
digraph {a → b}
[/dot]
Larger SVG
Larger SVG with unfitted graph
Larger SVG with unfitted normal sized graph
[dot border="1px solid black" width=200 height=300 fit=false ]
digraph {a -> b}
[/dot]
[dot border=“1px solid black” width=200 height=300 fit=false ]
digraph {a → b}
[/dot]
Larger SVG with unfitted downscaled graph
[dot border="1px solid black" width=200 height=300 fit=false scale=0.5]
digraph {a -> b}
[/dot]
[dot border=“1px solid black” width=200 height=300 fit=false scale=0.5]
digraph {a → b}
[/dot]
Larger SVG with unfitted upscaled graph
[dot border="1px solid black" width=200 height=300 fit=false scale=2]
digraph {a -> b}
[/dot]
[dot border=“1px solid black” width=200 height=300 fit=false scale=2]
digraph {a → b}
[/dot]
Larger SVG with fitted graph
Larger SVG with fitted unscaled graph
[dot border="1px solid black" width=200 height=300 fit=true]
digraph {a -> b}
[/dot]
[dot border=“1px solid black” width=200 height=300 fit=true]
digraph {a → b}
[/dot]
Larger SVG with fitted downscaled graph
[dot border="1px solid black" width=200 height=300 fit=true scale=0.5]
digraph {a -> b}
[/dot]
[dot border=“1px solid black” width=200 height=300 fit=true scale=0.5]
digraph {a → b}
[/dot]
Larger SVG with fitted upscaled graph
[dot border="1px solid black" width=200 height=300 fit=true scale=2]
digraph {a -> b}
[/dot]
[dot border=“1px solid black” width=200 height=300 fit=true scale=2]
digraph {a → b}
[/dot]
Smaller SVG
Smaller SVG with unfitted graph
Smaller SVG with unfitted normal sized graph
[dot border="1px solid black" width=50 height=50 fit=false ]
digraph {a -> b}
[/dot]
[dot border=“1px solid black” width=50 height=50 fit=false ]
digraph {a → b}
[/dot]
Smaller SVG with unfitted downscaled graph
[dot border="1px solid black" width=50 height=50 fit=false scale=0.5]
digraph {a -> b}
[/dot]
[dot border=“1px solid black” width=50 height=50 fit=false scale=0.5]
digraph {a → b}
[/dot]
Smaller SVG with unfitted upscaled graph
[dot border="1px solid black" width=50 height=50 fit=false scale=2]
digraph {a -> b}
[/dot]
[dot border=“1px solid black” width=50 height=50 fit=false scale=2]
digraph {a → b}
[/dot]
Smaller SVG with fitted graph
Smaller SVG with fitted unscaled graph
[dot border="1px solid black" width=50 height=50 fit=true]
digraph {a -> b}
[/dot]
[dot border=“1px solid black” width=50 height=50 fit=true]
digraph {a → b}
[/dot]
Smaller SVG with fitted downscaled graph
[dot border="1px solid black" width=50 height=50 fit=true scale=0.5]
digraph {a -> b}
[/dot]
[dot border=“1px solid black” width=50 height=50 fit=true scale=0.5]
digraph {a → b}
[/dot]
Smaller SVG with fitted upscaled graph
[dot border="1px solid black" width=50 height=50 fit=true scale=2]
digraph {a -> b}
[/dot]
[dot border=“1px solid black” width=50 height=50 fit=true scale=2]
digraph {a → b}
[/dot]
Options reference
The d3-graphviz options
All d3-graphviz options are supported. These are:
Option | Default value |
---|---|
convertEqualSidedPolygons |
true |
engine |
'dot' |
fade |
true |
fit |
false |
growEnteringEdges |
true |
height |
null |
keyMode |
'title' |
scale |
1 |
tweenPaths |
true |
tweenPrecision |
1 |
tweenShapes |
true |
useWorker |
true |
useSharedWorker |
true |
width |
null |
zoom |
true |
zoomScaleExtent |
[0.1, 10] |
zoomTranslateExtent |
[[-∞, -∞], [+∞, +∞]] |
Additional options
Option | Default value | Description |
---|---|---|
delay |
500 | Delay in milliseconds before starting each animated transition. |
duration |
1500 | Duration in milliseconds of each animated transition. |
ease |
cubic | Set the easing function of the transition. Allowed values are linear and cubic . |
verbose |
false | Show the DOT source code before the graph. |
border |
Sets the CSS border property on the graph SVG element. |
|
style |
Sets the HTML style attribute on the graph SVG element. | |
play |
true | Play animations once when they become visible for the first time. Can be paused with the Pause button to the left of the graph. |
repeat |
false | Play animations repeatedly. Can be stopped with the Stop button to the left of the graph. |
Implementation
The functionality described above is implemented by the D3 Graphviz Discourse Theme Component. It can be installed in any Discourse forum. See How do I install a Theme or Theme Component?.
Feedback
All feedback is welcome as comments below. If you have found a problem or want to suggest an enhancement, the preferred method is to file an issue at the GitHub repository where you can also see if it’s already covered by an issue filed by someone else. If it’s easier to show what you mean as a comment here at the forum that’s also ok, but it’s easier to track it at GitHub.