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.

VividD
  • 10,456
  • 6
  • 64
  • 111
Ashish Singh
  • 1,004
  • 11
  • 23

1 Answers1

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);
}
Ashish Singh
  • 1,004
  • 11
  • 23
  • Beautiful question, beautiful answer. – VividD Jan 11 '14 at 20:47
  • 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) – schnee Apr 30 '14 at 20:28
  • @schnee 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. – Ashish Singh May 02 '14 at 19:04
  • 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. – Dao Lam Jul 17 '14 at 18:55
  • @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. – Ashish Singh Jul 24 '14 at 07:02
  • 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. https://github.com/d3/d3/issues/2488 – mg1075 May 22 '17 at 05:01
  • @mg1075 Update the demo. Works now. – Ashish Singh May 22 '17 at 09:45
  • 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. – kimli Jun 22 '18 at 17:07
  • @kimli highlighting all the connections is what was needed not just the immediate neighbours – Ashish Singh Jul 20 '18 at 12:08
  • Any working example from a notebook Observable ? – PBrockmann May 08 '21 at 09:15
  • Starting from https://observablehq.com/@d3/sankey-diagram – PBrockmann May 08 '21 at 10:21
  • @pbrockmann https://observablehq.com/@git-ashish/sankey-diagram. Things remain same. – Ashish Singh May 08 '21 at 15:26
  • https://observablehq.com/@pbrockmann/sankey-diagram-with-highlighted-path Ok get my notebook working. Many thanks @AshishSingh Some changes to better fit my purpose. – PBrockmann May 10 '21 at 22:04