'plotly sankey diagram positioning

I'd like to add some annotations to Plotly Sankey diagram.
And I want to draw them right over the blocks of sankey nodes (with the same x-position) but couldn't find the way to do it, or even to find the X coordinates of nodes. (Think it would be better to get them and not to add manually, because number of sankey levels could change)

If we'll take this basic example, I want to add "A" "B" and "C" labels over corresponding nodes

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()


Solution 1:[1]

You can use fig.add_annotation() in this case. Add the following lines below line with fig.update_layout()

fig.add_annotation(dict(font=dict(color="black",size=12), x=0, y=1.06, showarrow=False, text='<b>A</b>'))
fig.add_annotation(dict(font=dict(color="black",size=12), x=0.5, y=1.06, showarrow=False, text='<b>B</b>'))
fig.add_annotation(dict(font=dict(color="black",size=12), x=1, y=1.06, showarrow=False, text='<b>C</b>'))

You will get the figure as follows. You can modify the code depending on your requirement. enter image description here

Solution 2:[2]

Here's an unnecessary expansion of a previous answer.

If we start with the basic diagram:

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.write_image("fig1.png")
fig.show()

Then add annotations. If we don't specify the location it will be in the middle of the plot.

fig.add_annotation(text='<b>DEFAULT</b>',font_color="red") # unspecified position

We can specify locations using x,y coordinates:

fig.add_annotation(x=0, y=0, text='<b>(0,0)</b>', font_color="red")
fig.add_annotation(x=1, y=1, text='<b>(1,1)</b>', font_color="red")

Now fig.show() gives us this: locations of (1,1) and (0,0) on plot

Now that we know the layout we can put the desired labels into a list and use that to position them automatically as follows:

lab_list = ['<b>A</b>','<b>B</b>','<b>C</b>']
for i, text in enumerate(lab_list):
    x_val = i / (len(lab_list)-1)
    fig.add_annotation(
        x=x_val, 
        y=1.06, 
        text=text,
        showarrow=False
    )

Now fig.show() yields the plot with the properly positioned annotations. enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 hbstha123
Solution 2 Arthur Morris