Sankey Diagram in Python
How to make Sankey Diagrams in Python with Plotly.
New to Plotly?
Plotly is a free and open-source graphing library for Python. We recommend you read our Getting Started guide for the latest installation or upgrade instructions, then move on to our Plotly Fundamentals tutorials or dive straight in to some Basic Charts tutorials.
A Sankey diagram is a flow diagram, in which the width of arrows is proportional to the flow quantity.
import plotly.graph_objects as go
fig = go.Figure(data=[go.Sankey(
node = dict(
pad = 15,
thickness = 20,
line = dict(color = "black", width = 0.5),
label = ["A1", "A2", "B1", "B2", "C1", "C2"],
color = "blue"
),
link = dict(
source = [0, 1, 0, 2, 3, 3], # indices correspond to labels, eg A1, A2, A1, B1, ...
target = [2, 3, 3, 4, 4, 5],
value = [8, 4, 2, 8, 4, 2]
))])
fig.update_layout(title_text="Basic Sankey Diagram", font_size=10)
fig.show()
More complex Sankey diagram with colored links¶
import plotly.graph_objects as go
import urllib, json
url = 'https://raw.githubusercontent.com/plotly/plotly.js/master/test/image/mocks/sankey_energy.json'
response = urllib.request.urlopen(url)
data = json.loads(response.read())
# override gray link colors with 'source' colors
opacity = 0.4
# change 'magenta' to its 'rgba' value to add opacity
data['data'][0]['node']['color'] = ['rgba(255,0,255, 0.8)' if color == "magenta" else color for color in data['data'][0]['node']['color']]
data['data'][0]['link']['color'] = [data['data'][0]['node']['color'][src].replace("0.8", str(opacity))
for src in data['data'][0]['link']['source']]
fig = go.Figure(data=[go.Sankey(
valueformat = ".0f",
valuesuffix = "TWh",
# Define nodes
node = dict(
pad = 15,
thickness = 15,
line = dict(color = "black", width = 0.5),
label = data['data'][0]['node']['label'],
color = data['data'][0]['node']['color']
),
# Add links
link = dict(
source = data['data'][0]['link']['source'],
target = data['data'][0]['link']['target'],
value = data['data'][0]['link']['value'],
label = data['data'][0]['link']['label'],
color = data['data'][0]['link']['color']
))])
fig.update_layout(title_text="Energy forecast for 2050<br>Source: Department of Energy & Climate Change, Tom Counsell via <a href='https://bost.ocks.org/mike/sankey/'>Mike Bostock</a>",
font_size=10)
fig.show()
Sankey Diagram in Dash¶
Dash is the best way to build analytical apps in Python using Plotly figures. To run the app below, run pip install dash
, click "Download" to get the code and run python app.py
.
Get started with the official Dash docs and learn how to effortlessly style & deploy apps like this with Dash Enterprise.
Sign up for Dash Club → Free cheat sheets plus updates from Chris Parmer and Adam Schroeder delivered to your inbox every two months. Includes tips and tricks, community apps, and deep dives into the Dash architecture. Join now.
import plotly.graph_objects as go
import urllib, json
url = 'https://raw.githubusercontent.com/plotly/plotly.js/master/test/image/mocks/sankey_energy.json'
response = urllib.request.urlopen(url)
data = json.loads(response.read())
fig = go.Figure(data=[go.Sankey(
valueformat = ".0f",
valuesuffix = "TWh",
node = dict(
pad = 15,
thickness = 15,
line = dict(color = "black", width = 0.5),
label = data['data'][0]['node']['label'],
color = data['data'][0]['node']['color']
),
link = dict(
source = data['data'][0]['link']['source'],
target = data['data'][0]['link']['target'],
value = data['data'][0]['link']['value'],
label = data['data'][0]['link']['label']
))])
fig.update_layout(
hovermode = 'x',
title=dict(text="Energy forecast for 2050<br>Source: Department of Energy & Climate Change, Tom Counsell via <a href='https://bost.ocks.org/mike/sankey/'>Mike Bostock</a>"),
font=dict(size = 10, color = 'white'),
plot_bgcolor='black',
paper_bgcolor='black'
)
fig.show()
Link Hover Color¶
New in 5.19
Set link.hovercolor
to change the colors of links on hover. link.hovercolor
accepts either one color, specified as a string, that will apply to all links, or a list of colors to specify different colors for each link. Here, we use a list to specify a different color for each link:
import plotly.graph_objects as go
fig = go.Figure(data=[go.Sankey(
node = dict(
pad = 15,
thickness = 20,
line = dict(color = "black", width = 0.5),
label = ["A1", "A2", "B1", "B2", "C1", "C2"],
color = "blue"
),
link = dict(
source = [0, 1, 0, 2, 3, 3],
target = [2, 3, 3, 4, 4, 5],
value = [8, 4, 2, 8, 4, 2],
hovercolor=["midnightblue", "lightskyblue", "gold", "mediumturquoise", "lightgreen", "cyan"],
))])
fig.update_layout(title_text="Basic Sankey Diagram", font_size=10)
fig.show()
Hovertemplate and customdata of Sankey diagrams¶
Links and nodes have their own hovertemplate, in which link- or node-specific attributes can be displayed. To add more data to links and nodes, it is possible to use the customdata
attribute of link
and nodes
, as in the following example. For more information about hovertemplate and customdata, please see the tutorial on hover text.
import plotly.graph_objects as go
fig = go.Figure(data=[go.Sankey(
node = dict(
pad = 15,
thickness = 20,
line = dict(color = "black", width = 0.5),
label = ["A1", "A2", "B1", "B2", "C1", "C2"],
customdata = ["Long name A1", "Long name A2", "Long name B1", "Long name B2",
"Long name C1", "Long name C2"],
hovertemplate='Node %{customdata} has total value %{value}<extra></extra>',
color = "blue"
),
link = dict(
source = [0, 1, 0, 2, 3, 3], # indices correspond to labels, eg A1, A2, A2, B1, ...
target = [2, 3, 3, 4, 4, 5],
value = [8, 4, 2, 8, 4, 2],
customdata = ["q","r","s","t","u","v"],
hovertemplate='Link from node %{source.customdata}<br />'+
'to node%{target.customdata}<br />has value %{value}'+
'<br />and data %{customdata}<extra></extra>',
))])
fig.update_layout(title_text="Basic Sankey Diagram", font_size=10)
fig.show()
Define Node Position¶
The following example sets node.x and node.y
to place nodes in the specified locations, except in the snap arrangement
(default behaviour when node.x
and node.y
are not defined) to avoid overlapping of the nodes, therefore, an automatic snapping of elements will be set to define the padding between nodes via nodepad. The other possible arrangements are: 1) perpendicular 2) freeform 3) fixed
import plotly.graph_objects as go
fig = go.Figure(go.Sankey(
arrangement = "snap",
node = {
"label": ["A", "B", "C", "D", "E", "F"],
"x": [0.2, 0.1, 0.5, 0.7, 0.3, 0.5],
"y": [0.7, 0.5, 0.2, 0.4, 0.2, 0.3],
'pad':10}, # 10 Pixels
link = {
"source": [0, 0, 1, 2, 5, 4, 3, 5],
"target": [5, 3, 4, 3, 0, 2, 2, 3],
"value": [1, 2, 1, 1, 1, 1, 1, 2]}))
fig.show()
Sankey Diagram with Arrow Links¶
New in 5.10
Create a Sankey diagram with arrow links by setting the arrowlen
attribute of link
:
import plotly.graph_objects as go
fig = go.Figure(go.Sankey(
arrangement='snap',
node=dict(
label=['A', 'B', 'C', 'D', 'E', 'F'],
x=[0.2, 0.1, 0.5, 0.7, 0.3, 0.5],
y=[0.7, 0.5, 0.2, 0.4, 0.2, 0.3],
pad=10,
align="right",
),
link=dict(
arrowlen=15,
source=[0, 0, 1, 2, 5, 4, 3, 5],
target=[5, 3, 4, 3, 0, 2, 2, 3],
value=[1, 2, 1, 1, 1, 1, 1, 2]
)
))
fig.show()
Node Alignment¶
New in 5.19
You can set the alignment of nodes using node.align
. Here are two examples with the same source
and target
. The first example has nodes aligned "left" and the second has nodes aligned "right". node.align
also supports "center" and "justify". "justify" is the default if node.align
is not set, and is similar to aligning to the "left", except that nodes without outgoing links are moved to the right of the figure.
import plotly.graph_objects as go
fig = go.Figure(go.Sankey(
arrangement='snap',
node=dict(
label=["0", "1", "2", "3", "4", "5"],
align='left'
),
link=dict(
arrowlen=15,
source=[0, 1, 4, 2, 1],
target=[1, 4, 5, 4, 3],
value=[4, 2, 3, 1, 2]
)
))
fig.show()
import plotly.graph_objects as go
fig = go.Figure(go.Sankey(
arrangement='snap',
node=dict(
label=["0", "1", "2", "3", "4", "5"],
align="right",
),
link=dict(
arrowlen=15,
source=[0, 1, 4, 2, 1],
target=[1, 4, 5, 4, 3],
value=[4, 2, 3, 1, 2]
)
))
fig.show()
Reference¶
See https://plotly.com/python/reference/sankey for more information and options!
What About Dash?¶
Dash is an open-source framework for building analytical applications, with no Javascript required, and it is tightly integrated with the Plotly graphing library.
Learn about how to install Dash at https://dash.plot.ly/installation.
Everywhere in this page that you see fig.show()
, you can display the same figure in a Dash application by passing it to the figure
argument of the Graph
component from the built-in dash_core_components
package like this:
import plotly.graph_objects as go # or plotly.express as px
fig = go.Figure() # or any Plotly Express function e.g. px.bar(...)
# fig.add_trace( ... )
# fig.update_layout( ... )
from dash import Dash, dcc, html
app = Dash()
app.layout = html.Div([
dcc.Graph(figure=fig)
])
app.run_server(debug=True, use_reloader=False) # Turn off reloader if inside Jupyter