Sankey diagram layout for visualizing flow between nodes.
Creates flow diagrams where the width of links is proportional to the flow quantity. Commonly used for showing energy transfers, money flows, or any directed weighted graph.
The layout is a port of d3-sankey: columns come from the alignment function over the longest-path depth of every node, one scale sizes both node heights and link widths, and the vertical positions are relaxed towards the ideal link positions with two-sided collision resolution.
Examples
nodes = [
%{id: "a", name: "Source A"},
%{id: "b", name: "Source B"},
%{id: "c", name: "Target C"},
%{id: "d", name: "Target D"}
]
links = [
%{source: "a", target: "c", value: 10},
%{source: "a", target: "d", value: 5},
%{source: "b", target: "c", value: 8},
%{source: "b", target: "d", value: 12}
]
sankey = Visualize.Layout.Sankey.new()
|> Visualize.Layout.Sankey.size(400, 300)
|> Visualize.Layout.Sankey.node_width(20)
|> Visualize.Layout.Sankey.node_padding(10)
|> Visualize.Layout.Sankey.compute(nodes, links)
# Access computed positions
sankey.nodes # Nodes with x0, x1, y0, y1 coordinates
sankey.links # Links with source/target nodes and path data
Summary
Functions
Computes the Sankey layout from nodes and links.
Generates a horizontal link path using cubic Bezier curves.
Sets the number of relaxation iterations
Generates SVG path data for a link
Generates SVG path data for all links
Sets a custom link sorting function.
Creates a new Sankey layout
Sets the node alignment method (d3-sankey's sankeyLeft, sankeyRight,
sankeyCenter and sankeyJustify).
Sets the vertical padding between nodes
Sets the node width
Returns the nodes grouped by layer
Sets the diagram size
Types
@type sankey_node() :: %{ :id => any(), optional(:name) => String.t(), optional(:x0) => number(), optional(:x1) => number(), optional(:y0) => number(), optional(:y1) => number(), optional(:value) => number(), optional(:depth) => non_neg_integer(), optional(:height) => non_neg_integer(), optional(:layer) => non_neg_integer(), optional(:source_links) => [map()], optional(:target_links) => [map()] }
@type t() :: %Visualize.Layout.Sankey{ height: number(), iterations: non_neg_integer(), link_sort: (sankey_link(), sankey_link() -> boolean()) | nil, links: [sankey_link()], node_align: :left | :right | :center | :justify, node_padding: number(), node_width: number(), nodes: [sankey_node()], width: number() }
Functions
@spec compute(t(), [sankey_node()], [sankey_link()]) :: t()
Computes the Sankey layout from nodes and links.
Returns the sankey struct with computed node positions and link paths.
@spec generate_link_path(sankey_link()) :: String.t()
Generates a horizontal link path using cubic Bezier curves.
This creates the characteristic curved flow appearance.
@spec iterations(t(), non_neg_integer()) :: t()
Sets the number of relaxation iterations
@spec link_path(sankey_link()) :: String.t()
Generates SVG path data for a link
Generates SVG path data for all links
@spec link_sort(t(), (sankey_link(), sankey_link() -> boolean()) | nil) :: t()
Sets a custom link sorting function.
Links are sorted vertically within their source/target nodes by this comparator (true
when the first link comes first). When nil, links follow the vertical order of the
node at their other end.
@spec new() :: t()
Creates a new Sankey layout
Sets the node alignment method (d3-sankey's sankeyLeft, sankeyRight,
sankeyCenter and sankeyJustify).
:left- every node at its depth (longest path from a source):right- every node atL - height(longest path to a sink), so sinks share the last column:center- a node with incoming links at its depth, a node with only outgoing links one column before its nearest target, an isolated node at 0:justify- every node without outgoing links in the last column, others at their depth (default)
Sets the vertical padding between nodes
Sets the node width
@spec nodes_by_layer(t()) :: [[sankey_node()]]
Returns the nodes grouped by layer
Sets the diagram size