C--C
C--C

Reputation: 11

Extract results from networkd3 sankey diagram

I'm new here and this is the second time I'm posting this because the previous post was deleted, I don't know what the issue was, would be great if you could state the reason before deleting the post.

So I'm trying again...

This question could be quite basic as I'm just starting to use networkd3, so excuse me for that. I tried looking online for help but unfortunately couldn't find anything. I was wondering if there is any specific way to extract the results of a networkd3 plot.

I'm trying to extract the order of the resulting nodes of the sankey plot in order to use it as an input to other plots but unable to figure out how to extract this information.

I understand that by using iterations=0 I can manually order the nodes but I want to get the ordered nodes so it looks more clean and easier to interpret.

Edit: Including a basic code I found on the internet and modified slightly for reference.

# Library
library(networkD3)
library(dplyr)
 
# A connection data frame is a list of flows with intensity for each flow
links <- data.frame(
  source=c("A","A", "B", "C", "C", "E"), 
  target=c("1","3", "3", "3", "2", "1"), 
  value=c(2,3, 2, 3, 1, 3)
  )
 
# From these flows we need to create a node data frame: it lists every entities involved in the flow
nodes <- data.frame(
  name=c(as.character(links$source), 
  as.character(links$target)) %>% unique()
)
 
# With networkD3, connection must be provided using id, not using real name like in the links dataframe.. So we need to reformat it.
links$IDsource <- match(links$source, nodes$name)-1 
links$IDtarget <- match(links$target, nodes$name)-1
 
# Make the Network
p <- sankeyNetwork(Links = links, Nodes = nodes,
              Source = "IDsource", Target = "IDtarget",
              Value = "value", NodeID = "name", 
              sinksRight=FALSE)

I would like to know if there is a possibility if one could extract the order of the target nodes from the sankey plot.

Upvotes: 1

Views: 120

Answers (1)

CJ Yetman
CJ Yetman

Reputation: 8848

Getting JavaScript to send a value back to R is not easy, but the shiny package can do this. So you could add some JavaScript to grab the information you want using htmlwidgets::onRender(), and send it back through shiny with something like this...

# Library
library(networkD3)
library(dplyr)

# A connection data frame is a list of flows with intensity for each flow
links <- data.frame(
  source=c("A","A", "B", "C", "C", "E"), 
  target=c("1","3", "3", "3", "2", "1"), 
  value=c(2,3, 2, 3, 1, 3)
)

# From these flows we need to create a node data frame: it lists every entities involved in the flow
nodes <- data.frame(
  name=c(as.character(links$source), 
         as.character(links$target)) %>% unique()
)

# With networkD3, connection must be provided using id, not using real name like in the links dataframe.. So we need to reformat it.
links$IDsource <- match(links$source, nodes$name)-1 
links$IDtarget <- match(links$target, nodes$name)-1

# Make the Network
p <- sankeyNetwork(Links = links, Nodes = nodes,
                   Source = "IDsource", Target = "IDtarget",
                   Value = "value", NodeID = "name", 
                   sinksRight=FALSE)


widget <- htmlwidgets::onRender(
  p,
  '
  function(el, x) {
    let sankey = this.sankey;
    let x_of_last_col = Math.max(...sankey.nodes().map(d => d.x));
    var nodes_in_last_col = sankey.nodes().filter(d => d.x == x_of_last_col);
    nodes_in_last_col = nodes_in_last_col.sort((a,b) => a.y > b.y);
    let json_output = JSON.stringify(nodes_in_last_col.map(d => [d.name, d.y]));
    Shiny.setInputValue("x", json_output);
  }
  '
)

node_order <- shiny::runApp(list(
  ui = shiny::bootstrapPage(shiny::textInput("x", "x"), sankeyNetworkOutput("plot")),
  server = function(input, output, session) {
    output$plot <- renderSankeyNetwork({widget});
    shiny::observeEvent(input$x, { shiny::stopApp(input$x) }, ignoreInit = TRUE)
  }
))

jsonlite::fromJSON(node_order)
#>      [,1] [,2]              
#> [1,] "1"  "9.99999999999999"
#> [2,] "3"  "173.571428571429"
#> [3,] "2"  "429.285714285714"

Upvotes: 1

Related Questions