0

First, let me start by saying that I've read How to assign levels to nodes in multi-level sankey diagram?

It helps but doesn't fully solve the issue.

Also, in my example code below I use the networkD3 package but I don't need to. Any package is fine with me so long as I'm able to place certain nodes at certain levels in the diagram.

Problem: I'm trying to draw a 3-level sankey diagram where each node is assigned to a "period" or level in the chart. The full chain of links would be something like Period 1-->Period 2-->Period 3. However, there may be cases where a Period 2 node is not connected to a Period 1 node (Period 2 --> Period 3) or where a Period 2 node is not connected to a Period 3 node (Period 1 --> Period 2).

I haven't figured out how to accomplish this on my own. The image below is what I'm trying to produce. enter image description here

Below is some code to reproduce the problem I'm running into:

(Note: this is a simplified version. My actual data contains 150 nodes, 5 Periods and many hundreds of links.)

library(dplyr)
library(networkD3)

# Create link data
links <- data.frame(source = c("A","A","B","C","D","E","G"),
                    target = c("D","E","D","F","H","H","I"),
                    nlink = c(12,27,10,5,1,5,10)
                    )

# Create node data
nodes <- data.frame(
  name=c(as.character(links$source), as.character(links$target)) %>% 
    unique()
)

# Assign periods to nodes
# I don't know how to actually use this to tell sankeyNetwork
# where to place the nodes but I'm including it here to help in problem solving 
period <- data.frame(period = c("Period 1", "Period 1", "Period 1",
                                "Period 2", "Period 2", "Period 2", "Period 2",
                                "Period 3", "Period 3"))
nodes$nodeGroup <- period$period

# match to numbers, not names
links$IDsource <- match(links$source, nodes$name)-1 
links$IDtarget <- match(links$target, nodes$name)-1

# Plot Sankey Network
p <- sankeyNetwork(
  Links = links,
  Nodes = nodes,
  Source = "IDsource",
  Target = "IDtarget",
  Value = "nlink",
  NodeID = "name",
  nodeWidth = 30,
  iterations = 5
)
p

enter image description here

You can see here that even though node "C" is a Period 1 node, it is placed with the Period 2 nodes. If I change the code to use "sinksRight = FALSE" as suggested in this thread: How to assign levels to nodes in multi-level sankey diagram? we get the following:

p <- sankeyNetwork(
  Links = links,
  Nodes = nodes,
  Source = "IDsource",
  Target = "IDtarget",
  Value = "nlink",
  NodeID = "name",
  nodeWidth = 30,
  sinksRight = FALSE,
  iterations = 5
)
p

enter image description here

Now you can see that the "C" node is with the other Period 1 nodes as it should be, but the "G" node is now over here too, when it's a Period 2 node and should be in-line with D, E, and F (while I should be in the Period 3 level in-line with H).

Is there a way for me to explicitly assign nodes to a specific level?

Obed
  • 403
  • 3
  • 12
  • 1
    You will not be able to do this with {networkD3} alone. The concept of a column or period or whatever you wanna call it is not a characteristic the {networkD3} accepts as an input because it determines a node's horizontal placement algorithmically. – CJ Yetman Aug 02 '22 at 15:05
  • Thanks @CJYetman, I thought that might be the case. I'm not wedded to networkd3 though as I don't need interactivity or a widget of any kind. I just need the actual diagram. Given that, is there another technique you'd suggest? – Obed Aug 02 '22 at 15:11
  • Is there a hacky way I could make a node/line invisible? – Obed Aug 03 '22 at 17:11

0 Answers0