Skip to main content

Using the QuickChart GraphViz API

GraphViz API

QuickChart is an open-source API that generates GraphViz charts. The API takes a graph description in the DOT language and renders it with the latest stable version of GraphViz, returning the output as PNG or SVG.

To get started, use the https://quickchart.io/graphviz endpoint. Here's a simple example:

https://quickchart.io/graphviz?graph=graph{a--b}

You'll notice that it defaults to SVG output. Let's change it to PNG and give it some dimensions so I can, for example, send it in an email:

https://quickchart.io/graphviz?format=png&width=100&height=150&graph=graph{a--b}

Examples

Directed graphs

Directed graphs or "digraphs" have edges that define a direction from one vertex to another. Here's our DOT definition for a straightforward directed graph:

digraph {
main->parse->execute;
main->init;
main->cleanup;
execute->make_string;
execute->printf
init->make_string;
main->printf;
execute->compare;
}

Pack it into the URL:

https://quickchart.io/graphviz?graph=digraph{main->parse->execute;main->init;main->cleanup;execute->make_string;execute->printf;init->make_string;main->printf;execute->compare;}

And it will render like so:

Node shapes and colors

GraphViz is incredibly flexible. There are 59 built-in node shapes available, and you can also edit colors and styles however you like:

digraph G {
size ="4,4";
main [shape=doubleoctagon];
main -> parse [weight=8];
parse -> execute;
main -> init [style=dotted];
main -> cleanup;
execute -> { make_string; printf}
init -> make_string;
edge [color=red]; // so is this
main -> printf [style=bold,label="100 times"];
make_string [label="make a\nstring"];
node [shape=star,style=filled,color=".7 .3 1.0"];
execute -> compare;
}

Let's put the above graph description in our API url:

https://quickchart.io/graphviz?graph=digraph{...}

This URL returns the following image:

Note that when sending a GET request, you should always URL encode your graph parameter in the API request. For more complex charts, this is a requirement.

Learn more about node shapes and styling from the official GraphViz documentation here.

Subgraphs

Subgraphs are an important tool in GraphViz that are best used to illustrate clusters of nodes. Here's an example graph created by Josh Hayes-Sheen:

digraph {
subgraph cluster_0 {
label="Subgraph A";
a -> b;
b -> c;
c -> d;
}

subgraph cluster_1 {
label="Subgraph B";
a -> f;
f -> c;
}
}

You can use a more elaborate subgraph to illustrate complex processes (from graphviz documentation):

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];
}

Record-based nodes

In contrast the polygon or shape based nodes we see above, you can create tabular "record" nodes that are split into several blocks.

Here's a simple example:

digraph structs {
node[shape=record]
struct1 [label="<f0> left|<f1> middle|<f2> right"];
struct2 [label="{<f0> one|<f1> two}" shape=Mrecord];
struct3 [label="hello\nworld |{ b |{c|<here> d|e}| f}| g | h"];
struct1:f1 -> struct2:f0;
struct1:f0 -> struct3:f1;
}

HTML-like nodes

Record nodes have fallen out of favor compared to HTML-like node labels, which allow you to put limited HTML markup in your graph description. Although it's much more verbose, it's more flexible than the record-based approach and yields more possibilities:

digraph G {
node [shape=plaintext]
a [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD PORT="c" BGCOLOR="gray">first</TD></TR>
<TR><TD>second</TD></TR>
<TR><TD>third</TD></TR>
</TABLE>>];
b [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD PORT="c" BGCOLOR="pink">first</TD></TR>
<TR><TD>second</TD></TR>
<TR><TD>third</TD></TR>
</TABLE>>];
a:c -> b:c;
}

Pack this graph description into the /graphviz?format=png endpoint and we get the following:

Layout engines

GraphViz is comprised by DOT, the language that describes the graph itself, and a set of programs that generate the graph layout. The default layout is also called dot, but there are many other layout programs available.

You can select a layout engine in the QuickChart API by adding a parameter layout=dot. Available layout engines include dot, fdp, neato, circo, twopi, and osage.

This section will use a simple example created by Rasmus Andersson to illustrate the difference between layout systems.

dot

The DOT layout engine is generally used to show hierarchical structure in directed graphs.

fdp

This is generally used for undirected graphs. It uses a spring model with a force-directed approach to determine the position of each node.

Here's the same graph as above except undirected, using the fdp layout engine, /graphviz?layout=fdp&graph=...:

neato

Neato is another layout engine generally used for undirected graphs. It uses a spring model as well. The neato engine tends to do better than fdp engine when rendering clusters and cyclic subgraphs, spacing things out more evenly and making cycles stand out more.

circo

The circo layout engine is for circular layout of graphs, as the name suggests. This is used to generate graphs that show cyclic structure and biconnected components. The algorithm attempts to minimize edge crossings within the circle by placing edges on the perimeter of the circle if possible.

twopi

The twopi layout engine generates radial layouts, drawing nodes in concentric circles depending on their distance from a root node.

One node is chosen as the center (in this case, E) and is placed at the origin. All nodes of the same distance from the center are placed on the same concentric circle around the center.

This graph, for example, makes it easy to see that nodes A, H, and O are the farthest from E.

osage

The osage layout engine is for large undirected graphed with multiple subgraphs. It separates the graph into "levels" (clusters) and lays out each level in a rectangle. The rectangles are then packed together. Within each rectangle, the subgraph/cluster is laid out.

This makes the separation and composition of graph clusters very distinct in the visualization.

Our example doesn't have subgraphs, so the effect of the osage layout engine is just that our nodes are arranged in a table, and the edges turn into a mess.

patchwork

The patchwork layout engine for GraphViz draws the graph as a squarified treemap. The clusters on the graph are used to create the tree.

Here's our graph with the layout=patchwork parameter:

API parameters

The https://quickchart.io/graphviz endpoint supports HTTP GET requests with the following parameters:

  • graph - the DOT graph description (required)
  • layout - the name of the graph layout engine (default dot)
  • format - the output format, either png or svg (default svg)
  • width - width of image, applicable to png only (defaults to fit)
  • height - height of image, applicable to png only (defaults to fit)

The API also supports HTTP POST requests with JSON payloads. Here's an example payload:

{
"graph": "digraph {a->b}",
"layout": "dot",
"format": "svg"
}

Example requests

You can hit the GET or POST endpoint using any HTTP client package available in your preferred programming language.

Here's an example of a POST request in node.js:

const fetch = require('node-fetch');

const body = {
graph: 'digraph {a->b}',
layout: 'dot',
format: 'svg',
};

const response = await fetch('https://quickchart.io/graphviz', {
method: 'post',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' },
});

// Response contains an SVG. Write it to file or send it someplace else.
const svg = await response.text();
console.log(svg);

The same request in Python:

import requests

body = {
"graph": "digraph {a->b}",
"layout": "dot",
"format": "svg"
}

r = requests.post('https://quickchart.io/graphviz', json=body)

# r.text is sufficient for SVG. Use `r.raw` for png images
svg = r.text

And finally, here's a generic equivalent using curl:

# In payload.json:
{
"graph": "digraph {a->b}",
"layout": "dot",
"format": "png"
}

# Then run:
curl -X POST 'https://quickchart.io/graphviz' -H 'Content-Type: application/json' -d @payload.json -o render.png

Give it a try now and reach out if you have any questions!


Ian Webster

About the author

Ian Webster is a software engineer and former Googler based in San Mateo, California. He has helped Google, NASA, and governments around the world improve their data pipelines and visualizations. In 2018, Ian created QuickChart, a collection of open-source APIs that support data visualization efforts.

Email · LinkedIn · Twitter