Highlight all connected paths from start to end of a sankey diagram using networkD3

时间:2018-12-19 11:24:19

标签: r d3.js sankey-diagram htmlwidgets networkd3

I would like to produce a Sankey-diagram using the networkD3 package in R that has the functionality as described in this question, and the "highlight_node_links" function in the answer:

d3 Sankey - Highlight all connected paths from start to end

I'm a beginner with both R and Javascript and my problem is that I cannot make the above javascript function work with my R code. I have checked Highlight all connected paths from start to end in Sankey graph using R question too, but unfortunately I couldn't solve it based on the answer there either. I do understand I need to use htmlwidgets::onRender, but cannot figure out how.

A small sample data and the network generated from it:

links = data.frame(source = c("me",  "you", "she", "p1",  "p1",  "p2",  "p2"), target = c("p1",  "p2",  "p1",  "p2",  "b1",  "b1",  "b2"), weight = c(20, 10, 30, 40, 60, 50, 50)) 
nodes <- data.frame(name = c(links$source, links$target) %>% unique()) 
links$IDsource = match(links$source, nodes$name)-1 
links$IDtarget = match(links$target, nodes$name)-1

sn <- sankeyNetwork(Links = links, 
                      Nodes = nodes,
                      Source = "IDsource", 
                      Target = "IDtarget",
                      Value = "weight",  
                      NodeID = "name",  
                      sinksRight = TRUE)

And the way I tried to include the highlight_node_links function (that I defined earlier unchanged from the above link):

    htmlwidgets::onRender(
  sn,
  '
        function(el, x) {
          var link = d3.selectAll(".link");
         var node = d3.selectAll(".node");
        node.on("mousedown.drag", null);
        node.on("click",highlight_node_links);

  function highlight_node_links(node,i){

  var remainingNodes=[],
  nextNodes=[];

  var stroke_opacity = 0;
  if( d3.select(this).attr("data-clicked") == "1" ){
  d3.select(this).attr("data-clicked","0");
  stroke_opacity = 0.2;
  }else{
  d3.select(this).attr("data-clicked","1");
  stroke_opacity = 0.5;
  }

  var traverse = [{
  linkType : "sourceLinks",
  nodeType : "target"
  },{
  linkType : "targetLinks",
  nodeType : "source"
  }];

  traverse.forEach(function(step){
  node[step.linkType].forEach(function(link) {
  remainingNodes.push(link[step.nodeType]);
  highlight_link(link.id, stroke_opacity);
  });

  while (remainingNodes.length) {
  nextNodes = [];
  remainingNodes.forEach(function(node) {
  node[step.linkType].forEach(function(link) {
  nextNodes.push(link[step.nodeType]);
  highlight_link(link.id, stroke_opacity);
  });
  });
  remainingNodes = nextNodes;
  }
  });
  }

  function highlight_link(id,opacity){
  d3.select("#link-"+id).style("stroke-opacity", opacity)
         }}'
)

1 个答案:

答案 0 :(得分:1)

运行代码时,我收到警告消息...

Warning message:
It looks like Source/Target is not zero-indexed. This is required in JavaScript
 and so your plot may not render.

告诉您问题的根源是... linksnodes数据帧未正确创建。

您可以通过在创建stringsAsFactors = FALSE数据框的data.frame命令中添加links作为参数来轻松解决此问题。

工作示例...

library(networkD3)
library(htmlwidgets)
library(dplyr)

links = data.frame(
  source = c("me",  "you", "she", "p1",  "p1",  "p2",  "p2"),
  target = c("p1",  "p2",  "p1",  "p2",  "b1",  "b1",  "b2"),
  weight = c(20, 10, 30, 40, 60, 50, 50),
  stringsAsFactors = FALSE
)
nodes <-
  data.frame(name = c(links$source, links$target) %>% unique())
links$IDsource = match(links$source, nodes$name) - 1
links$IDtarget = match(links$target, nodes$name) - 1

sn <- sankeyNetwork(
  Links = links,
  Nodes = nodes,
  Source = "IDsource",
  Target = "IDtarget",
  Value = "weight",
  NodeID = "name",
  sinksRight = TRUE
)

htmlwidgets::onRender(
  sn,
  '
        function(el, x) {
          var link = d3.selectAll(".link");
         var node = d3.selectAll(".node");
        node.on("mousedown.drag", null);
        node.on("click",highlight_node_links)}'
)

enter image description here