Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 938
Joyce Bombay Avatar asked Aug 02 '13 20:08

Joyce Bombay


1 Answers

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.

like image 55
Sean Easter Avatar answered Oct 28 '22 06:10

Sean Easter