1

With plotly sankey diagram I want to locate a node in the middle using code, but since this node does not have a flow for another node, plotly places it at the right end. I have the next code:

import plotly.graph_objects as go

fig1 = go.Figure(
    go.Sankey(
        node={"label": ["A", "B", "C", "D", "E", "F"]},
        link={
            "source": [0, 0, 0, 1, 2, 2],
            "target": [1, 2, 3, 4, 4, 5],
            "value": [20, 10, 20, 20, 5, 15]
        }        
    )
)
fig1.show()

The output: enter image description here

For example, for the image I would like to locate node D below nodes B and C.

gabriel11
  • 80
  • 6

2 Answers2

0

You can create groups of nodes using the groups key in the node dictionary:

fig1 = go.Figure(
    go.Sankey(
        node={
             "label": ["A", "B", "C", "D", "E", "F"],
             "groups": [[0], [1, 2, 3], [4, 5]]
        },
        link={
            "source": [0, 0, 0, 1, 2, 2],
            "target": [1, 2, 3, 4, 4, 5],
            "value": [20, 10, 20, 20, 5, 15]
        }        
    )
)
Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
  • Thanks, but gave me an error: `ValueError: Invalid value of type 'builtins.int' received for the 'groups[0]' property of sankey.node Received value: 0 The 'groups' property is an info array that may be specified as: * a 2D list where: The 'groups[i][j]' property is a number and may be specified as: - An int or float` – gabriel11 Feb 09 '22 at 19:07
  • @gabriel11. I've never used plotly, so stabbing in the dark here. Updated with a better understanding of the docs. – Mad Physicist Feb 09 '22 at 19:22
  • The output merge the nodes in three groups, but I want them apart (splitted) – gabriel11 Feb 09 '22 at 19:43
  • @gabriel11. Can you post a picture of what it looks like? – Mad Physicist Feb 09 '22 at 20:21
0

This is not technically an answer as it uses another package (pyAlluv) that creates matplotlib figures.

The package needs to be installed directly from github, for example with:

pip install --upgrade --no-deps git+https://github.com/tools4digits/pyalluv.git

The example is an adaptation from one of the existing examples:

import numpy as np
from pyalluv import Alluvial
import matplotlib.pyplot as plt

ext = [10, ]  # start at t1 with a single node containing 10 elements
flows = [[[5],  # flow form node 1 at t1 to node 1 at t2
          [2],  # flow from node 1 at t1 to node 2 at t2
          [3]],  # ...
         [[4, 0, 0],  # flows from nodes 1, 2, 3 at t2 to node 1 at t3
          [1, 0, 3]]]  # flows from nodes 1, 2, 3 at t2 to node 2 at t3
alluv = Alluvial(x=['t1', 't2', 't3'], flows=flows, ext=ext, width=0.2, yoff=0, layout=['top', 'optimized', 'top'])

plt.show()

enter image description here

However, note that the package is indicated to be work in progress

It allows for quite some customization, that is not really documented though:

from pyalluv import Alluvial
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ext = [10, ]
flows = [[[5],
          [2],
          [3]],
         [[4, 0, 0],
          [1, 0, 3]]]
alluv = Alluvial(ax=ax, x=['t1', 't2', 't3'], flowprops={'fc':'gray', 'alpha':0.4}, ec='gray')
diag0 = alluv.add(flows=flows, ext=ext, width=0.2, yoff=0,
                 layout=['top', 'optimized', 'top'])
diag0.get_block((1,0)).set_facecolor('red')
diag0.get_block((1,1)).set_facecolor('purple')
diag0.get_block((1,2)).set_facecolor('green')
diag0.get_block((2,0)).set_facecolor('orange')
diag0.get_block((2,1)).set_facecolor('lightblue')
alluv.finish()

plt.show()

enter image description here

j-i-l
  • 10,281
  • 3
  • 53
  • 70
  • Thanks! But it sent me an error: `ImportError: cannot import name 'Alluvial' from 'pyalluv'`. – gabriel11 Feb 09 '22 at 21:57
  • Oh right! I forgot to mention: The package needs to be installed. You can simply do `pip install --upgrade --no-deps git+https://github.com/tools4digits/pyalluv.git` will add it to the answer. It uses 'numpy' and 'matplotlib' which need to be installed separately if the command is run with the `--no-deps` flag. – j-i-l Feb 09 '22 at 23:31