Render Graphviz graphs directly in your posts

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.

References

1 Like

thanks for all the hints and tutorial, I provided some feedbacks on github, I link it here to encourage users to follow the link and check the open and closed tickets, many of what I thought of was already covered

1 Like

Thanks @wassfila. I’ve now fixed


At least my version of it. Please let me know if it works for you.
1 Like

Yes, it does work now, I could not crash it with any of the combinations that did hang it before, it keeps showing a red debug message, then recovers as soon as it has a correct content, very robust and convenient for wysiwyg editing.
Amazing, I wish all the bugs I report get closed that fast :slight_smile: you should get a forum badge for that.

Thank you so much @wassfila.

Well you know, sometimes the only way to get feedback from your users is introducing bugs that you already have a solution for :stuck_out_tongue_winking_eye:.

Joking apart, it would have been even faster if I didn’t have to code for money during business hours :weary:

I really appreciate you taking the time to reproduce it so detailed :pray: :medal_sports:

1 Like