D3 highlight selected node, and its links to parent and ancestors in a force directed graph

Joyce Bombay picture Joyce Bombay · Aug 2, 2013 · Viewed 10.4k times · Source

I would like to highlight the links and nodes to the parent node in a graph when the child node is hovered. I took inspiration from The New York Times 'Paths to the white house':

enter image description here

I have seen the answer to this question with this Fiddle using:

var node = svg.selectAll(".node")
    .data(graph.nodes)
   .enter()
    .append("g")
    .attr("class", function(d) { return "node " + d.name + " " + d.location; })
    .call(force.drag)
    .on("mouseover", function(d) { 
        // if(isConnected(d, o)) {
        d3.select(this).select("circle").style("stroke-width", 6);               
        var nodeNeighbors = graph.links.filter(function(link) {
            return link.source.index === d.index || link.target.index === d.index;
        })
        .map(function(link) {
             return link.source.index === d.index ? link.target.index : link.source.index;
        });               
        svg.selectAll('circle').style('stroke', 'gray');
        svg.selectAll('circle').filter(function(node) {
            return nodeNeighbors.indexOf(node.index) > -1;
        })
        // }
    .on("mouseover", function(d) { 
        //   I would like to insert an if statement to do all of
        //   these things to the connected nodes
        // if(isConnected(d, o)) {
        d3.select(this).select("circle").style("stroke-width", 6); 
        d3.select(this).select("circle").style("stroke", "orange");
        // }
    })
    .on("mouseout",  function(d) { 
        // if(isConnected(d, o)) {
        d3.select(this).select("circle").style("stroke-width", 1.5); 
        d3.select(this).select("circle").style("stroke", "gray"); 
        // }
    });

Though they're using source and target, I wonder if it's also possible, and how it would be done, with a network diagram (force-directed graph) using parent and children?

Answer

Sean Easter picture Sean Easter · Mar 26, 2014

I've done something similar by adapting the functions found in this example. The trick is to build selections that work on only the links you'd like to highlight. Here's a snippet of my code:

function linkMouseover(d){
  chart.selectAll(".node").classed("active", function(p) { return d3.select(this).classed("active") || p === d.source || p === d.target; });
          }
// Highlight the node and connected links on mouseover.
function nodeMouseover(d) {
 chart.selectAll(".link").classed("active", function(p) { return d3.select(this).classed("active") || p.source === d || p.target === d; });
            chart.selectAll(".link.active").each(function(d){linkMouseover(d)})
            d3.select(this).classed("active", true);
          }

This force-directed example uses the terminology source and target—I don't imagine there's much distinction between source-target and parent-child. You should be able to make it work by editing the above, such that the .each() and .classed() callbacks operate only on the highlighted node, its (multiple generations of) children, and links between them.