Home > database >  d3 force graph, conditionally rendering nodes depending on amount of connected links
d3 force graph, conditionally rendering nodes depending on amount of connected links

Time:05-26

I have a force-directed graph with nodes that vary in size depending on how many links they are connected to.

What I would like to do is the following : Make nodes render conditionally so that those with "d.weight" under 21 append a text element, and those equal or above 21 append a circle element.

Below is my code that does not work. The problem may come from the "test" variable.. Any help is more than welcome

        var node = g
        .selectAll(".circle-group")
        .data(nodes)
        .join(enter => {
          node = enter.append("g")        
          .attr("class", "circle-group")


          var test = function(d){ link.filter(function(l) {
          return l.source.index == d.index || l.target.index == d.index
          }).size();  }


            //NODE BACKGROUND CIRCLE
          node.append("circle")
          .attr("class", "background") 
          .style("fill", "#e7c203")
          .attr("r", function(d) {     
          d.weight = link.filter(function(l) {
          return l.source.index == d.index || l.target.index == d.index
          }).size();      
          if(d.weight < 2){return "2px"}
          else if(d.weight >= 2 && d.weight < 6){return "5px"}
          else if(d.weight >= 6 && d.weight < 21){return "10px"}
          else if(d.weight >= 21){return "15px"}
          else{return "200px"}
          })
           
           //NODE TEXT FOREGROUND
          if(test < 21){ 
            node.append("text")
            .attr("text-anchor", "middle")
            .attr("dominant-baseline", "central") 
            .text(function(d){return d.id})
            .attr("fill", "white")
            .attr('stroke', 'white')
            .attr('stroke-width', '0.1px')
            .attr("y", -7)
            .style("font-size", "5px")

          //NODE IMAGE FOREGROUND
          }else{ 
            node.append("circle")
            .attr("class", "foreground") 
            .style("fill", d => `url(#${d.id})`)
            .attr("r", function(d) {      
            d.weight = link.filter(function(l) {
            return l.source.index == d.index || l.target.index == d.index
            }).size();      
            if(d.weight < 2){return "2px"}
            else if(d.weight >= 2 && d.weight < 6){return "5px"}
            else if(d.weight >= 6 && d.weight < 21){return "10px"}
            else if(d.weight >= 21){return "15px"}
            else{return "200px"}
            }) 
          }
            
          node.attr("stroke", "#e7c203").call(drag(simulation));
        })

CodePudding user response:

Ok so I finally figured out on my own.

The trick was to filter the nodes and then append the desired element. In my case, since i wanted to append different elements, I had to filter twice (once per condition)

Here is the fixed code below:


var node = g
        .selectAll(".circle-group")
        .data(nodes)
        .join(enter => {
          node = enter.append("g")        
          .attr("class", "circle-group")


          var test = function(d){ link.filter(function(l) {
          return l.source.index == d.index || l.target.index == d.index
          }).size();  }


            //NODE BACKGROUND CIRCLE
          node.append("circle")
          .attr("class", "background") 
          .style("fill", "#e7c203")
          .attr("r", function(d) {     
          d.weight = link.filter(function(l) {
          return l.source.index == d.index || l.target.index == d.index
          }).size();      
          if(d.weight < 2){return "2px"}
          else if(d.weight >= 2 && d.weight < 6){return "5px"}
          else if(d.weight >= 6 && d.weight < 21){return "10px"}
          else if(d.weight >= 21){return "15px"}
          else{return "200px"}
          })
           
           //NODE TEXT FOREGROUND
             node.filter(function(d){ return d.weight<6 }).append("text")
            .attr("text-anchor", "middle")
            .attr("dominant-baseline", "central") 
            .text(function(d){return d.id})
            .attr("fill", "white")
            .attr('stroke', 'white')
            .attr('stroke-width', '0.1px')
            .attr("y", -7)
            .style("font-size", "5px")

          //NODE IMAGE FOREGROUND
         node.filter(function(d){ return d.weight>5 }).append("circle")
            .attr("class", "foreground") 
            .style("fill", d => `url(#${d.id})`)
            .attr("r", function(d) {      
            d.weight = link.filter(function(l) {
            return l.source.index == d.index || l.target.index == d.index
            }).size();      
            if(d.weight < 2){return "2px"}
            else if(d.weight >= 2 && d.weight < 6){return "5px"}
            else if(d.weight >= 6 && d.weight < 21){return "10px"}
            else if(d.weight >= 21){return "15px"}
            else{return "200px"}
            }) 
          
            
          node.attr("stroke", "#e7c203").call(drag(simulation));
        })

  • Related