Skip to main content

Sankey

Basic Configuration

Sankey is a popular kind of flow diagram that visualizes flows between multiple nodes. To define a Sankey diagram you'll need to have data about its nodes and flows between them.

component.tsx
import { VisSingleContainer, VisSankey } from '@unovis/react'

function Component(props) {
const data: SankeyData = props.data

return (
<VisSingleContainer data={data}>
<VisSankey/>
</VisSingleContainer>
)
}
Loading...

Specifically, Sankey accepts data in the following form:

type SankeyData<NodeDatum, LinkDatum> = {
nodes: NodeDatum[];
links: LinkDatum[];
}

The minimal configuration for a Link datum contains source and target properties, which correspond to the starting and ending nodes of the link, and a numerical value.

type SankeyLink = {
source: string | number | SankeyNode;
target: string | number | SankeyNode;
value?: number;
}

Note that the value is not required, but recommended since by default Sankey will use this property to calculate the width of each link. Alternatively, you can provide a numeric accessor function to the linkValue property.

Nodes

While there are no explicitly required properties for NodeDatum, a common configuration looks like:

type SankeyNode = {
id: string;
color: string;
label: string;
}

Alternatively, you can provide accessor functions to id, nodeColor, nodeLabel properties to achieve the same effect.

Component Sizing

Sankey supports three different sizing options that can be set via SingleContainer: Sizing.Fit (default), Sizing.Extend and Sizing.FitWidth.

By default, SingleContainer and Sankey will take all the available space of its parent HTML element. However, if you set SingleContainer's sizing to Sizing.Extend (or "extend"), the diagram will be able to go beyond its parent size and become scrollable. In that case you'll be able to control the diagram size by using the following properties: nodeWidth, nodeHorizontalSpacing, nodeMinHeight, nodeMaxHeight, and nodePadding (see Node Sizing).

The Sizing.FitWidth (or "fit_width") option is similar to the Sizing.Extend option, but the whole component will be scaled down proportionally to fit horizontally into its container; vertical scrolling will remain available.

Labels

The following customization options are available for Node labels:

Label Background

For a chart with many nodes, it might be useful to add a background by setting the labelBackground property to true:

<VisSankey labelBackground={true}/>
Loading...

Label Fitting

By default, node labels that exceed the width constraint will be trimmed to exclude the middle. For the following properties, the default configuration for Sankey looks like:

{
labelFit: FitMode.Trim,
labelMaxWidth: 70,
labelTrimMode: TrimMode.Middle,
labelExpandTrimmedOnHover: true,
}

For overflowing labels, the default configuration renders as:

Loading...

FitMode.Wrap

You can disable trimming by setting labelFit to FitMode.Wrap or 'wrap', which forces line breaking:

component.tsx
import { VisSingleContainer, VisSankey } from '@unovis/react'

function Component(props) {
const data: SankeyData = props.data
const label = (d: SankeyNode) => `Long node name : ${d.id}`

return (
<VisSingleContainer data={data}>
<VisSankey label={label} labelFit="wrap"/>
</VisSingleContainer>
)
}
Loading...
tip

When labelFit is set to FitMode.Wrap, you can change which characters to denote a new line with the labelTextSeparator property. (default: [' ', '-']).

FitMode.Trim

You can the labelTrimMode property to change which portion of the labels you want to trim:

<VisSankey labelTrimMode="start" label={label}/>
Loading...

Label Placement

The following properties deal with node label placement:

  • labelPosition, which corresponds to the horizontal placement relative to the node (default: Position.Auto);
  • labelVerticalAlign, for vertical alignment (default: VerticalAlign.Middle);
  • labelVisibility, which accepts a custom function that when returns false, the label will be hidden altogether.

Sub-labels

You can add a secondary label with the subLabel property. Sub-label color and font size can be configured with the subLabelColor and subLabelFontSize properties.

component.tsx
function Component(props) {
const data: SankeyData = props.data
const label = (d: SankeyNode) => d.id
const subLabel = (d: SankeyNode) => d.val

return (
<VisSankey label={label} subLabel={subLabel}/>
)
}
Loading...

By default, sub-labels will be placed below the main labels. However, if you set the subLabelPlacement property to SankeySubLabelPlacement.Inline (or "inline"), they will be placed right next to the main label on the left or on the right (depending on labelPosition).

<VisSankey
label={label}
subLabel={subLabel}
subLabelPlacement="inline"
/>
Loading...

Node Customization

Node Alignment

You can override the default node alignment with the nodeAlign property. Accepted values are SankeyNodeAlign.Left, SankeyNodeAlign.Right, SankeyNodeAlign.Center and SankeyNodeAlign.Justify (default)

<VisSankey nodeAlign="left"/>
Loading...

Node Sizing

By default, the height of the nodes will be calculated automatically based on the height of Sankey's container and the nodePadding property. The width of the nodes can be set with the nodeWidth configuration option (measurement is in pixels).

<VisSankey nodeWidth={100} nodePadding={20}/>
Loading...

If sizing of SingleContainer is set to Sizing.Extend or Sizing.FitWidth (see Component Sizing), you can control the height of the nodes by setting the nodeMinHeight and nodeMaxHeight properties. Note that those options are approximate since d3-sankey doesn't allow setting the node height explicitly.

Node Icons

Provide an accessor function to nodeIcon to add a label/symbol over the node itself. Customize the icon's color with iconColor:

component.tsx
function Component(props) {
const data: SankeyData = props.data
const nodeIcon = (d: NodeDatum) => d.currencySymbol

return (
<VisSankey nodeIcon={nodeIcon} iconColor="white"/>
)
}
Loading...

Sorting

By default, Sankey will sort the links based on their value in descending order from top to bottom. To change the order of the links, provide a custom sorting function to linkSort.

Alternatively, if you want to set the order of the nodes explicitly, you can provide a custom sorting function to nodeSort. It'll take precedence over the linkSort function.

See the following example, where nodes are sorted by property x, a number in the range [0,4], which also configures the node's color:

component.tsx
function Component(props) {
const data: SankeyData = props.data
const nodeSort = (node1: NodeDatum, node2: NodeDatum) => node1.x - node2.x
const nodeColor = (d: SankeyNode) => `var( -- vis - color${d.x})`

return (
<VisSankey nodeColor={nodeColor} nodeSort={nodeSort}/>
)
}
Loading...

Events

The following selectors are available for events:

import { Sankey } from '@unovis/ts'

const events = {
[Sankey.selectors.node]: { ... }
[Sankey.selectors.nodeGroup]: { ... }
[Sankey.selectors.link]: { ... },
[Sankey.selectors.label]: { ... },
[Sankey.selectors.sublabel]: { ... },
[Sankey.selectors.labelGroup]: { ... },
}

CSS Variables

All supported CSS variables and their default values

/* Links */
--vis-sankey-link-cursor: default;
--vis-sankey-link-color: var(--vis-color-main-light);
--vis-sankey-link-opacity: 0.5;
--vis-sankey-link-hover-opacity: 1.0;
/* Nodes */
--vis-sankey-node-cursor: default;
--vis-sankey-node-color: var(--vis-color-main);
--vis-sankey-node-label-color: #575c65;
--vis-sankey-node-opacity: 0.9;
--vis-sankey-node-hover-opacity: 1.0;
/* Node Labels */
--vis-sankey-node-label-background-fill-color: #ffffff;
--vis-sankey-node-label-background-stroke-color: #eaeaea;
--vis-sankey-node-label-background-opacity: 0.9;
--vis-sankey-node-label-color: #575c65;
--vis-sankey-node-label-cursor: default;
--vis-sankey-node-label-font-weight: 600;
--vis-sankey-node-label-font-size: 12px;
--vis-sankey-node-label-text-decoration: none;
--vis-sankey-node-sublabel-font-size: 10px;
--vis-sankey-node-sublabel-font-weight: 500;
/* Icons */
--vis-sankey-icon-size: 22px;
--vis-sankey-icon-color: #ffffff;
--vis-sankey-icon-stroke-opacity: 0.6;
--vis-sankey-icon-font-family: FontAwesome;
/* --vis-sankey-label-font-family: */ // Undefined by default to allow proper fallback to var(--vis-font-family)
 
/* Dark Theme */
--vis-dark-sankey-link-color: var(--vis-color-main-dark);
--vis-dark-sankey-node-color: var(--vis-color-main);
--vis-dark-sankey-node-label-color: #eaeaea;
--vis-dark-sankey-node-label-background-fill-color: #292b34;
--vis-dark-sankey-node-label-background-stroke-color: #575c65;
--vis-dark-sankey-icon-color: #292b34;

Component Props

NameTypeDescription
* required property