Skip to content

Sankey diagram

A Sankey diagram is a flow chart. For generic flow chart related information, please visit “Flow charts” tutorial.

Sankey diagram is drawn horizontal (links flow from left to right) by default.

We can change it using series’ orientation setting:

let series = root.container.children.push(
am5flow.Sankey.new(root, {
sourceIdField: "from",
targetIdField: "to",
valueField: "value",
orientation: "vertical"
})
);

Nodes (colored bands) are 10 pixel wide by default.

We can use series setting nodeWidth to change that:

let series = root.container.children.push(
am5flow.Sankey.new(root, {
sourceIdField: "from",
targetIdField: "to",
valueField: "value",
nodeWidth: 5
})
);

Nodes in flow diagrams are represented by their own series, accessible via read-only property nodes which is an object of type SankeyNodes.

It subsequently has a property rectangles which is a list of all nodes in series.

Since it’s a “list template”, we can use its template property to set any setting for the node, which is of type RoundedRectangle:

series.nodes.rectangles.template.setAll({
fillOpacity: 0.5,
stroke: am5.color(0x000000),
strokeWidth: 1,
cornerRadiusTL: 4,
cornerRadiusTR: 4,
cornerRadiusBL: 4,
cornerRadiusBR: 4
});
Open in CodePen

In Sankey diagrams, node ids (and names) are derived from link data (via sourceIdField and targetIdField).

In some cases, we might need more than just node id which comes from Sankey data.

For that we can set own data on series.nodes.data:

series.nodes.data.setAll([
{ id: "A", name: "Node A" },
{ id: "B", name: "Node B" },
{ id: "C", name: "Node C" }
]);

Node series (which is SankeyNodes) is automatically set up for these data fields:

Data field Default value Comment
idField "id" ID of the node.
nameField "id" Name of the node.
fillField "fill" Fill color for the node.

We can modify those to suit our data:

series.nodes.setAll({
idField: "id",
nameField: "name"
});
series.nodes.data.setAll([
{ id: "A", name: "Node A" },
{ id: "B", name: "Node B" },
{ id: "C", name: "Node C" }
]);

We can also specify custom colors for nodes via node data:

series.nodes.data.setAll([
{ id: "A", name: "Node A", fill: am5.color(0xFF621F) },
{ id: "B", name: "Node B", fill: am5.color(0x297373) },
{ id: "C", name: "Node C", fill: am5.color(0x946B49) }
]);

The fill color will be lookup up in a "fill" field of the data. If we need to use something else, we will need to configure node series’ fillField as well:

series.nodes.setAll({
idField: "id",
nameField: "name",
fillField: "color"
});
series.nodes.data.setAll([
{ id: "A", name: "Node A", color: am5.color(0xFF621F) },
{ id: "B", name: "Node B", color: am5.color(0x297373) },
{ id: "C", name: "Node C", color: am5.color(0x946B49) }
]);
Open in CodePen

Sankey diagrams display a tiny gap between each node by default.

We can control the size of it using series’ nodePadding setting.

It accepts a numeric value in degrees.

let series = root.container.children.push(
am5flow.Sankey.new(root, {
sourceIdField: "from",
targetIdField: "to",
valueField: "value",
nodePadding: 5
})
);

Sankey will position all of its nodes aligned to left, which might not work for complex flows.

To control it, we have a Sankey setting: nodeAlign.

It accepts four values: "left" (default), "right", "center", and "justify".

let series = root.container.children.push(
am5flow.Sankey.new(root, {
sourceIdField: "from",
targetIdField: "to",
valueField: "value",
nodeAlign: "justify"
})
);
Open in CodePen

Nodes are draggable and click-togglable in Sankey diagram by default.

To disable it, simply set draggable: false and toggleKey: "none" settings on node template:

series.nodes.nodes.template.setAll({
draggable: false, // disables dragging
toggleKey: "none" // disables toggling
});

Sankey links are smooth curves by default.

We can configure how “tight” the curve is via series linkTension setting.

With default of 0.5 it accepts a numeric value between 0 (zero) and 1 (one).

The smaller the number, the more loose the curve. 1 will result in maximum tension, i.e. perfectly straight line.

let series = root.container.children.push(
am5flow.Sankey.new(root, {
sourceIdField: "from",
targetIdField: "to",
valueField: "value",
linkTension: 1
})
);

We can configure links using series property links.template. Via template, we can set any SankeyLink setting.

series.links.template.setAll({
fillOpacity: 0.5
});

Sankey links can be colored in a number of ways via link template’s fillStyle setting:

series.links.template.setAll({
fillStyle: "solid"
});

These values are available for fillStyle:

fillStyle

Comment

Example

"solid"

Solid color.

"gradient" (default)

Gradient from source node color to target node color.

"source"

Source node color.

"target"

Target node color.

A bend (or control point) is a position where link’s elbows bend forming an “elbow”.

By default this happens 20% of either end of the link.

We can control it using link setting: controlPointDistance.

It accepts numeric values between 0 (zero) and 1 (one). The smaller the number the closer the elbow will be to the ends of the link.

series.links.template.setAll({
controlPointDistance: 0.4
});

Links on a Sankey diagram are sorted using built-in fuzzy logic.

We can modify the logic using linkSort setting.

It accepts two types of values:

  1. null. Setting it to null will make links appear exactly in the same order as they are set in data.
  2. function. The setting can also accept a reference to a custom function that accepts two parameters with a D3 sankey link objects.

Setting linkSort to null will make the links appear in exact same order as they are defined in data:

let series = root.container.children.push(
am5flow.Sankey.new(root, {
sourceIdField: "from",
targetIdField: "to",
valueField: "value",
linkSort: null
})
);

linkSort can also accept a reference to a custom sort function.

Similarly to JavaScript’s Array.sort(a, b) function, linkSort function will receive two instances of a D3 link objects, and should return -1 if the first link should precede the second, 1 if it’s the other way around, or 0 if they are both equal in priority.

let series = root.container.children.push(am5flow.Sankey.new(root, {
sourceIdField: "from",
targetIdField: "to",
valueField: "value",
paddingRight: 50,
linkSort: function(a, b) {
if (a.value < b.value) return -1;
if (a.value > b.value) return 1;
return 0;
}
}));

The above will order all links by their value in descending order.

Sankey diagram will display a label next to its nodes by default.

Labels in Sankey diagram are attached to nodes, so they can be configured via nodes sub-series, specifically nodes.labels.template:

series.nodes.labels.template.setAll({
fontSize: 20,
maxWidth: 150,
oversizedBehavior: "wrap"
});

Refer to Label class reference for a full list of available settings.

To change label content, we only need to set text property of the label template:

series.nodes.labels.template.setAll({
text: "[bold]{name}[/] ({sumOutgoing})"
});

Contents of the label can include data placeholders (codes in curly brackets that will be replaced by actual data) and in-line formatting blocks (formatting instructions enclosed in square brackets).

For available data placeholder fields refer to ISankeyNodesDataItem.

Labels are positioned to the right (or bottom) of the node by default.

There are a few settings that can be used to control position of the label:

Setting key Comment
x Horizontal position: absolute pixel values or percent relative to node height.
y Vertical position: absolute pixel values or percent relative to node height.
centerX Horizontal center of the label: absolute pixel value or percent relative to the width of the label.
centerY Vertical center of the label: absolute pixel value or percent relative to the width of the label.
paddingTop Top padding in pixels.
paddingRight Right padding in pixels.
paddingBottom Bottom padding in pixels.
paddingLeft Left padding in pixels.

The below code will put labels inside and up top on the node:

series.nodes.labels.template.setAll({
x: am5.percent(50),
centerX: am5.percent(50),
y: am5.percent(0),
centerY: am5.percent(0),
paddingLeft: 0,
paddingRight: 0
});
Open in CodePen

To disable labels, we can simply set their visible to false:

series.nodes.labels.template.set("visible", false);

Links will display a tooltip when hovered/touched. The default content is "{sourceId} - {targetId}: {value}" which will show source node ID, followed by target node ID, and link value.

To change it, we can use link’s tooltipText setting:

series.links.template.setAll({
tooltipText: "From: [bold]{sourceId}[/]\nTo: [bold]{targetId}\nValue: [bold]{value}[/]"
});

Contents of the tooltip can include data placeholders (codes in curly brackets that will be replaced by actual data) and in-line formatting blocks (formatting instructions enclosed in square brackets).

For available data placeholder fields refer to ISankeyDataItem.

To add tooltips to nodes, simple set tooltipText on node template:

series.nodes.rectangles.template.setAll({
tooltipText: "[bold]{name}[/]\nOutgoing: {sumOutgoing}\nIncoming: {sumIncoming}"
});

For available data placeholder fields refer to ISankeyNodesDataItem.

Template fields can also be used to configure various diagram elements, such as node rectangles and link graphics.

series.nodes.rectangles.template.set("templateField", "nodeSettings");
series.links.template.set("templateField", "linkSettings");
series.nodes.data.setAll([
{ id: "A", nodeSettings: { fill: am5.color(0xFF621F), stroke: am5.color(0x000000 } },
{ id: "B", nodeSettings: { fill: am5.color(0x297373), stroke: am5.color(0x000000 } },
{ id: "C", nodeSettings: { fill: am5.color(0xFF621F), stroke: am5.color(0x000000 } },
])
series.data.setAll([
{ from: "A", to: "B", value: 10, linkSettings: { fill: am5.color(0x297373), fillOpacity: 0.5, fillStyle: "solid" } },
{ from: "B", to: "C", value: 8, linkSettings: { fill: am5.color(0xFF621F), fillOpacity: 0.5, fillStyle: "solid" } }
]);
Open in CodePen