d3 Sankey - Highlight all connected paths from start to end
Asked Answered
H

1

10

I'm trying to highlight all the connected links and links of their target nodes till the end of the layout.

The first level of highlighting can be easily achieved as follows -

On node click, call highlight_paths(1);

function highlight_paths(stroke_opacity) {
    return function(d,i){
        d.sourceLinks.forEach(function(srcLnk){
            d3.select("#link"+srcLnk.id).style("stroke-opacity", stroke_opacity);
        });
        d.targetLinks.forEach(function(srcLnk){
            d3.select("#link"+srcLnk.id).style("stroke-opacity", stroke_opacity);
        });
    }
}

But I'm not yet able to write correctly a recursive algorithm to get all the sourceLinks and targetLinks of each of the connected source & target nodes.

All thoughts are appreciated!

Thanks.

Helprin answered 5/10, 2013 at 8:58 Comment(3)
This should help.Soddy
Thanks @LarsKotthoff! This surely would've helped but I just found the solution so posting it here.Helprin
Thanks @milen-pavlov for the formatting! :)Helprin
H
21

I was going through the sankey layout code and found a Breadth First Search implementation for traversing the layout nodes. Some knowledge on BFS here - http://www.cse.ohio-state.edu/~gurari/course/cis680/cis680Ch14.html

Purely based on that, here is the function to highlight all the paths from the clicked node in both the directions - Forward ( Target ) and Backward (Source)

Hope this helps someone!

Working examples -

http://bl.ocks.org/git-ashish/8959771

https://observablehq.com/@git-ashish/sankey-diagram

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);
}
Helprin answered 8/10, 2013 at 5:26 Comment(13)
Beautiful question, beautiful answer.Melmela
Really nice, but I have noticed that if you click a node, then the hover-highlighting seems broken. Click a node and then click again (to turn off the traverse). Then hover is not working for the edges that got highlighted. (Chrome, OSX)Loo
@Loo Its fixed now. Same link. On hover, the link stroke-opacity is changed. But as the click highlighting applies stroke opacity at the element in-line level, the hover style was not getting applied. I've now made that !important so that it is always considered. Doing this via css is the way to go.Helprin
What is node[step.linkType]? step.linkType returns either "sourceLinks" or "targetLinks" but what is node[sourceLinks]? I keep getting "undefined" for that line of code.Aerophagia
@DaoLam consider "sourceLinks" or "targetLinks" like tree branches which give you nodes for sources and targets of the clicked node respectively. If you can point us to a fiddle, that would be good. Otherwise, I assume "node" in your case is not pointing to the proper dataset / datum.Helprin
Does this demo actually function with complete highlighting of paths? I am not seeing full path highlighting in the demo block. It seems like the click event is not firing at all. github.com/d3/d3/issues/2488Maxwellmaxy
@Maxwellmaxy Update the demo. Works now.Helprin
I don't think this is correct because it's highlighting all connections of the next level in the flow, rather than just the nodes and links that are truly connected to the source.Biogenesis
@Biogenesis highlighting all the connections is what was needed not just the immediate neighboursHelprin
Any working example from a notebook Observable ?Choplogic
Starting from observablehq.com/@d3/sankey-diagramChoplogic
@pbrockmann observablehq.com/@git-ashish/sankey-diagram. Things remain same.Helprin
observablehq.com/@pbrockmann/… Ok get my notebook working. Many thanks @AshishSingh Some changes to better fit my purpose.Choplogic

© 2022 - 2024 — McMap. All rights reserved.