Search code examples
rplotlysankey-diagram

Income to outcome flow chart in Sankey plotly R


I would like to create a sankey diagram in Plotly R. In this graph I would like to show the income flow to outcome flow with a budget bar in the middle like show similar to the answer here. Unfortunately that is not made in Plotly. I tried to create this plot, but I don't understand the structure of source and target in the plotly package. Here I create a reproducible example:

library(plotly)

df <- data.frame(
  label = c("Income1", "Income2", "Income2", "Budget", "Outcome1", "Outcome1", "Outcome2"),
  color = c("green", "green", "green", "blue", "red", "red", "red"),
  source = c(1,2,2,0,3,3,4),
  target = c(0,0,0,0,0,0,0),
  value =  c(8,4,2,0,8,4,2)
)
df

fig <- plot_ly(
  type = "sankey",
  orientation = "h",
  node = list(
    label = df$label,
    color = df$color,
    pad = 15,
    thickness = 20,
    line = list(
      color = "black",
      width = 0.5
    )
  ),
  link = list(
    source = df$source,
    target = df$target,
    value =  df$value
  )
)

fig

Output:

enter image description here

This doesn't create my expected output. I would like to have the income flows on the left, the budget in the middle and outcome on the right. So I was wondering if anyone knows how to do this in Plotly R?


Solution

  • You can define your nodes in label counting from 0. Then define your flows in a seperate table: here reference the labels' source and target using the node index.

    out

    library(plotly)
    
    links <- data.frame(
      source = c(0, 1, 2, 2),          # From which node (0-indexed)
      target = c(2, 2, 3, 4),          # To which node (0-indexed)
      value =  c(8, 6, 8, 6)           # Value/width of the flow
    )
    
    plot_ly(
      type = "sankey",
      orientation = "h",
      node = list( # 0         # 1         #2         #3          #4
        label = c("Income1", "Income2", "Budget", "Outcome1", "Outcome2"),
        color = c("green", "green", "blue", "red", "red"),
        pad = 15,
        thickness = 20,
        line = list(
          color = "black",
          width = 0.5
        )
      ),
      
      link = list(
        source = links$source,
        target = links$target,
        value = links$value
      )
    )