Search code examples
javascriptd3.jsd3-force-directed

Why won't my links show?


Below is some code I have used to generate a force directed graph to show the following data. The nodes, zoom and pan out features work however the lines wont show between my nodes when there is a link. Data in json format:

{
    "nodes": [
        {
            "id": "100 ladrillos",
            "group": "1",
            "Tags": "[]",
            "Size": "\"1-10"
        },
        {
            "id": "3d business solutions",
            "group": "2",
            "Tags": "[]",
            "Size": "\"1-10"
        },
        {
            "id": "a\u00e3\u0090apps",
            "group": "3",
            "Tags": "[]",
            "Size": "\"1-10"
        },
        {
            "id": "adjoint inc.",
            "group": "4",
            "Tags": "[]",
            "Size": "\"1-10"
        },
        {
            "id": "airbd, inc.",
            "group": "4",
            "Tags": "[]",
            "Size": "\"1-10"
        }
    ],
 "links":[
   {
      "source":"100 ladrillos",
      "target":"3d business solutions",
      "value":20
    },
    {
       "source":"100 ladrillos",
       "target": "a\u00e3\u0090apps",
       "value":10
     },
     {
        "source":"100 ladrillos",
        "target":"adjoint inc.",
        "value":10
      },
     {
        "source":"a\u00e3\u0090apps",
        "target":"airbd, inc.",
        "value":10
      } 
   ]
}

D3 visual code:

<!DOCTYPE html>
<meta charset = "utf-8">
<style>

.links line {
  stroke : #999;
  stroke-opacity: 0.6;
}

.nodes circle {
  stroke: black;
  stroke-width: 0px;
}

</style>
<svg width = "1000" height = "1000"></svg>
<script src = "https://d3js.org/d3.v4.min.js"></script>
<script>

//Creating somewhere to put my force directed graph

var svg = d3.select("svg"),
    width = +svg.attr("width"),
    height = +svg.attr("height");

var radius = 15;

d3.json("data.json", function(data) {
  var nodes = data.nodes
  var links = data.links

  var simulation = d3.forceSimulation()
      .nodes(nodes);

  var link_force = d3.forceLink(links)
                        .id(function(d){return d.id;});

  var charge_force = d3.forceManyBody()
      .strength(-100);

  var center_force = d3.forceCenter(width/2,height/2);

  simulation
        .force("charge_force", charge_force)
        .force("center_force", center_force)
        .force("links",link_force)
  ;

  simulation.on("tick",tickActions);

  var g = svg.append("g")
      .attr("class","everything");

  var link = g.append("g")
          .attr("class","links")
        .selectAll("line")
        .data(links)
        .enter().append("line")
          .attr("stroke-width",2)
          .style("stroke",linkColour);

  var node = g.append("g")
          .attr("class","nodes")
          .selectAll("circle")
          .data(nodes)
          .enter()
          .append("circle")
          .attr("r",radius)
          .attr("fill", circleColour);

  var drag_handler = d3.drag()
      .on("start",drag_start)
      .on("drag", drag_drag)
      .on("end",drag_end);

  drag_handler(node);

  var zoom_handler = d3.zoom()
      .on("zoom", zoom_actions);

  zoom_handler(svg);

  function circleColour(d){
    if (d.group == 0){
      return "blue";
    } else {
      return "red";
    }
    }

    function linkColour(d){
        if(d.group == "4"){
            return "green";
        } else {
            return "red";
        }
    }

  function drag_start(d){
  if (!d3.event.active) simulation.alphaTarget(0.3).restart();
    d.fx = d.x
    d.fy = d.y;
  }

  function drag_drag(d){
    d.fx = d3.event.x;
    d.fy = d3.event.y;
  }

  function drag_end(d){
    if (!d3.event.active) simulation.alphaTarget(0);
    d.fx = null;
    d.fy = null;
  }

  function zoom_actions(){
    g.attr("transform", d3.event.transform)

  }

  function tickActions(){
    node
      .attr("cx",function(d) { return d.x;})
      .attr("cy",function(d){ return d.y;});

    link
      .attr("x1", function(d) { return d.source.x;})
      .attr("y1", function(d) { return d.source.y;})
      .attr("x2", function(d) { return d.source.x;})
      .attr("y2", function(d) { return d.source.y;});
  }
});
</script>

Please can someone explain why the links wont show and how I can fix this issue? Thank you.


Solution

  • You're setting the same values for x1 and x2, the same for y1 and y2:

    link.attr("x1", function(d) { return d.source.x;})
        .attr("y1", function(d) { return d.source.y;})
        .attr("x2", function(d) { return d.source.x;})
        .attr("y2", function(d) { return d.source.y;});
    

    Instead of that, it should be:

    link.attr("x1", function(d) { return d.source.x;})
        .attr("y1", function(d) { return d.source.y;})
        .attr("x2", function(d) { return d.target.x;})//'target' here
        .attr("y2", function(d) { return d.target.y;});//'target' here
    

    Here is your code with that change (and a smaller SVG):

    <!DOCTYPE html>
    <meta charset="utf-8">
    <style>
      .links line {
        stroke: #999;
        stroke-opacity: 0.6;
      }
    
      .nodes circle {
        stroke: black;
        stroke-width: 0px;
      }
    
    </style>
    <svg width="500" height="300"></svg>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script>
      //Creating somewhere to put my force directed graph
    
      var svg = d3.select("svg"),
        width = +svg.attr("width"),
        height = +svg.attr("height");
    
      var radius = 15;
    
      var data = {
        "nodes": [{
            "id": "100 ladrillos",
            "group": "1",
            "Tags": "[]",
            "Size": "\"1-10"
          },
          {
            "id": "3d business solutions",
            "group": "2",
            "Tags": "[]",
            "Size": "\"1-10"
          },
          {
            "id": "a\u00e3\u0090apps",
            "group": "3",
            "Tags": "[]",
            "Size": "\"1-10"
          },
          {
            "id": "adjoint inc.",
            "group": "4",
            "Tags": "[]",
            "Size": "\"1-10"
          },
          {
            "id": "airbd, inc.",
            "group": "4",
            "Tags": "[]",
            "Size": "\"1-10"
          }
        ],
        "links": [{
            "source": "100 ladrillos",
            "target": "3d business solutions",
            "value": 20
          },
          {
            "source": "100 ladrillos",
            "target": "a\u00e3\u0090apps",
            "value": 10
          },
          {
            "source": "100 ladrillos",
            "target": "adjoint inc.",
            "value": 10
          },
          {
            "source": "a\u00e3\u0090apps",
            "target": "airbd, inc.",
            "value": 10
          }
        ]
      };
    
      var nodes = data.nodes
      var links = data.links
    
      var simulation = d3.forceSimulation()
        .nodes(nodes);
    
      var link_force = d3.forceLink(links)
        .id(function(d) {
          return d.id;
        });
    
      var charge_force = d3.forceManyBody()
        .strength(-100);
    
      var center_force = d3.forceCenter(width / 2, height / 2);
    
      simulation
        .force("charge_force", charge_force)
        .force("center_force", center_force)
        .force("links", link_force);
    
      simulation.on("tick", tickActions);
    
      var g = svg.append("g")
        .attr("class", "everything");
    
      var link = g.append("g")
        .attr("class", "links")
        .selectAll("line")
        .data(links)
        .enter().append("line")
        .attr("stroke-width", 2)
        .style("stroke", linkColour);
    
      var node = g.append("g")
        .attr("class", "nodes")
        .selectAll("circle")
        .data(nodes)
        .enter()
        .append("circle")
        .attr("r", radius)
        .attr("fill", circleColour);
    
      var drag_handler = d3.drag()
        .on("start", drag_start)
        .on("drag", drag_drag)
        .on("end", drag_end);
    
      drag_handler(node);
    
      var zoom_handler = d3.zoom()
        .on("zoom", zoom_actions);
    
      zoom_handler(svg);
    
      function circleColour(d) {
        if (d.group == 0) {
          return "blue";
        } else {
          return "red";
        }
      }
    
      function linkColour(d) {
        if (d.group == "4") {
          return "green";
        } else {
          return "red";
        }
      }
    
      function drag_start(d) {
        if (!d3.event.active) simulation.alphaTarget(0.3).restart();
        d.fx = d.x
        d.fy = d.y;
      }
    
      function drag_drag(d) {
        d.fx = d3.event.x;
        d.fy = d3.event.y;
      }
    
      function drag_end(d) {
        if (!d3.event.active) simulation.alphaTarget(0);
        d.fx = null;
        d.fy = null;
      }
    
      function zoom_actions() {
        g.attr("transform", d3.event.transform)
    
      }
    
      function tickActions() {
        node
          .attr("cx", function(d) {
            return d.x;
          })
          .attr("cy", function(d) {
            return d.y;
          });
    
        link
          .attr("x1", function(d) {
            return d.source.x;
          })
          .attr("y1", function(d) {
            return d.source.y;
          })
          .attr("x2", function(d) {
            return d.target.x;
          })
          .attr("y2", function(d) {
            return d.target.y;
          });
      }
    
    </script>