Francesca
Francesca

Reputation: 93

Python plotly sankey and determine the order of the nodes

I am drawing a a sankey diagram where values go from 1 start node to 5 notes (A, B, C, D and E). I would like the nodes to be plotted in alphabetical order and I thought this could be achieved by my code but this is not the case as you can see from running my code - how can I make sure that A is followed by B, and B followed by C etc.?

I have Python 3.9 and updated plotly to version 4.12.0 but it did not help. I run the code in both Jupyter notebook and in Spyder (4.15) but the order of the nodes is off - can you advice how I can specify the order within the code?

import plotly.graph_objects as go
import plotly.express as px

source = [0, 0, 0, 0, 0]

target = [1, 2, 3, 4, 5]


value = [356, 16, 39, 6, 88]

label = ['Start', 'A', 'B', 'C', 'D', 'E']


color_node = ['#EBBAB5', 
'#EBBAB5', '#FEF3C7', '#A6E3D7','#98FB98', '#DDA0DD','#EBBAB5', '#FEF3C7', '#A6E3D7','#98FB98', '#DDA0DD','#EBBAB5', '#FEF3C7', '#A6E3D7','#98FB98', '#DDA0DD','#EBBAB5', '#FEF3C7', '#A6E3D7','#98FB98', '#DDA0DD','#EBBAB5', '#FEF3C7', '#A6E3D7','#98FB98', '#DDA0DD']
color_link = ['#EBBAB5', '#FEF3C7', '#A6E3D7','#98FB98', '#DDA0DD', 
'#EBBAB5', '#FEF3C7', '#A6E3D7','#98FB98', '#DDA0DD','#EBBAB5', '#FEF3C7', '#A6E3D7','#98FB98', '#DDA0DD','#EBBAB5', '#FEF3C7', '#A6E3D7','#98FB98', '#DDA0DD','#EBBAB5', '#FEF3C7', '#A6E3D7','#98FB98', '#DDA0DD','#EBBAB5', '#FEF3C7', '#A6E3D7','#98FB98', '#DDA0DD']

link = dict(source=source, target=target, value = value, color = color_link)
node = dict(label = label, pad=30, thickness=5, color = color_node)


data = go.Sankey(link = link, node = node)
fig = go.Figure(data)
fig.show()

Upvotes: 2

Views: 4758

Answers (1)

eindzl
eindzl

Reputation: 143

You can make use of this feature.

For example, this does the trick, although it's fairly manual:

n = 1/4
link = dict(source=source, target=target, value = value, color = color_link)
node = dict(label = label, 
            x = [0, 1, 1, 1, 1, 1],
            y = [0, 0*n, 1*n, 2*n, 3*n, 4*n],
            pad=30, 
            thickness=5, 
            color = color_node)

data = go.Sankey(
    link = link, 
    node = node,
    arrangement = "snap", 
)
fig = go.Figure(data)
fig.show()

What I did is just specify the position of the nodes: x==0 for the first column and x==1 for the second. For the y's I used even spacing between 0 and 1 for the nodes in the second column. I expected some overlapping of nodes, but it seems the logic in plotly.js solves that for you.

You can do the trick programmatically by specifying two lists of labels:

label_l = ['Start', ]
label_r = [ 'A', 'B', 'C', 'D', 'E']
...
node = dict(label = label_l + label_r, 
            x = [0, ]*len(label_l) + [1,]*len(label_r),
            y = list(np.linspace(0,1,len(label_l))) + list(np.linspace(0,1,len(label_r))),
            pad=30, 
            thickness=5, 
            color = color_node)

However, I don't guarantee it works for more complex cases.

Upvotes: 4

Related Questions