Phurich.P
Phurich.P

Reputation: 1416

D3 link circle by node's names

just getting started with D3. I am currently doing the network trading project which requires me to join nodes with other nodes depends the json file.

My json file looks like this.

{
    "nodes": [
        {  
           "id": "site01",
           "x": 317.5,
           "y": 282.5
        },
        {
          "id": "site02",
          "x": 112,
          "y": 47
       },
       {
          "id": "site03",
          "x": 69.5,
          "y": 287
       },
   ]
   "links": [
       {  
          "node01": "site01", 
          "node02": "site02", 
          "amount": 170
       },
       {  
          "node01": "site01", 
          "node02": "site03", 
          "amount": 100
       },
       {  
          "node01": "site02", 
          "node02": "site03", 
          "amount": 70
       },
   ]
}

What I am able to do write now is to plot the position of all the sites in nodes.

Here is my code.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <script src="https://d3js.org/d3.v4.min.js"></script>
  </head>
  <body>
    <script type="text/javascript">
      var w = 1200;
      var h = 800;
      var svg = d3.select("body").append("svg").attr("width",w).attr("height", h);
      var lines = svg.attr("class", "line")
      d3.json("data.json", function(error, data) {
        console.log(data);
        var circles = svg.selectAll("foo")
          .data(data.nodes)
          .enter()
          .append("circle")
          .attr("cx", function(d) {return d.x;})
          .attr("cy", function(d) {return d.y;})
          .attr("r", 20)
          .append("title") // For hover effect
          .text(function(d) { return "The site is " + d.id; });
        var lines = svg.selectAll("foo")
          .data(data.links)
          .enter()
          .append("line")
          .attr("x1", function(d) {
              return circles.filter(function(e) {
                  return e.id === d.node01
              }).attr("cx")
          })
          .attr("x2", function(d) {
              return circles.filter(function(e) {
                  return e.id === d.node02
              }).attr("cx")
          })
          .attr("y1", function(d) {
              return circles.filter(function(e) {
                  return e.id === d.node01
              }).attr("cy")
          })
          .attr("y2", function(d) {
              return circles.filter(function(e) {
                  return e.id === d.node02
              }).attr("cy")
          })
          .attr("stroke", "gray");
        circles.raise();
      });
    </script>
  </body>
</html>

My question is how can I possibly draw a line between 2 sites as describe in "links" in my json file. Also, how can I change the radius of the circle based on the amount describe in "links". For example, if site01 and site02 has a link, therefore the radius of those 2 nodes would be the same.

Edit - change to current version

Thank you,

Upvotes: 1

Views: 1292

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102188

When I first read your question's title I thought "ok, OP wants a force directed chart", and that's why I asked about D3 v4.x in the comments...

However, it seems to me that you don't want a force directed: you already have the circles' positions. You just want to link them.

That being the case, you can filter the circles' selection to get the lines' x1, x2, y1 and y2:

var lines = svg.selectAll("foo")
    .data(data.links)
    .enter()
    .append("line")
    .attr("x1", function(d) {
        return circles.filter(function(e) {
            return e.id === d.node01
        }).attr("cx")
    })
    .attr("x2", function(d) {
        return circles.filter(function(e) {
            return e.id === d.node02
        }).attr("cx")
    })
    .attr("y1", function(d) {
        return circles.filter(function(e) {
            return e.id === d.node01
        }).attr("cy")
    })
    .attr("y2", function(d) {
        return circles.filter(function(e) {
            return e.id === d.node02
        }).attr("cy")
    })
    .attr("stroke", "gray");

Here is the demo using your code and that selection for the lines:

var data = {
  "nodes": [{
    "id": "site01",
    "x": 317.5,
    "y": 282.5
  }, {
    "id": "site02",
    "x": 112,
    "y": 47
  }, {
    "id": "site03",
    "x": 69.5,
    "y": 287
  }],
  "links": [{
    "node01": "site01",
    "node02": "site02",
    "amount": 170
  }, {
    "node01": "site01",
    "node02": "site03",
    "amount": 100
  }, {
    "node01": "site02",
    "node02": "site03",
    "amount": 70
  }]
};

var w = 400;
var h = 320;
var svg = d3.select("body").append("svg").attr("width", w).attr("height", h);
var lines = svg.attr("class", "line")

var circles = svg.selectAll("foo")
  .data(data.nodes)
  .enter()
  .append("circle")
  .attr("cx", function(d) {
    return d.x;
  })
  .attr("cy", function(d) {
    return d.y;
  })
  .attr("r", 20);

circles.append("title")
  .text(function(d) {
    return "The site is " + d.id;
  });

var lines = svg.selectAll("foo")
  .data(data.links)
  .enter()
  .append("line")
  .attr("x1", function(d) {
    return circles.filter(function(e) {
      return e.id === d.node01
    }).attr("cx")
  })
  .attr("x2", function(d) {
    return circles.filter(function(e) {
      return e.id === d.node02
    }).attr("cx")
  })
  .attr("y1", function(d) {
    return circles.filter(function(e) {
      return e.id === d.node01
    }).attr("cy")
  })
  .attr("y2", function(d) {
    return circles.filter(function(e) {
      return e.id === d.node02
    }).attr("cy")
  })
  .attr("stroke", "gray");
<script src="https://d3js.org/d3.v4.min.js"></script>

And here the same code, but with the lines behind the circles:

var data = {
  "nodes": [{
    "id": "site01",
    "x": 317.5,
    "y": 282.5
  }, {
    "id": "site02",
    "x": 112,
    "y": 47
  }, {
    "id": "site03",
    "x": 69.5,
    "y": 287
  }],
  "links": [{
    "node01": "site01",
    "node02": "site02",
    "amount": 170
  }, {
    "node01": "site01",
    "node02": "site03",
    "amount": 100
  }, {
    "node01": "site02",
    "node02": "site03",
    "amount": 70
  }]
};

var w = 400;
var h = 320;
var svg = d3.select("body").append("svg").attr("width", w).attr("height", h);
var lines = svg.attr("class", "line")

var circles = svg.selectAll("foo")
  .data(data.nodes)
  .enter()
  .append("circle")
  .attr("cx", function(d) {
    return d.x;
  })
  .attr("cy", function(d) {
    return d.y;
  })
  .attr("r", 20);

circles.append("title")
  .text(function(d) {
    return "The site is " + d.id;
  });

var lines = svg.selectAll("foo")
  .data(data.links)
  .enter()
  .append("line")
  .attr("x1", function(d) {
    return circles.filter(function(e) {
      return e.id === d.node01
    }).attr("cx")
  })
  .attr("x2", function(d) {
    return circles.filter(function(e) {
      return e.id === d.node02
    }).attr("cx")
  })
  .attr("y1", function(d) {
    return circles.filter(function(e) {
      return e.id === d.node01
    }).attr("cy")
  })
  .attr("y2", function(d) {
    return circles.filter(function(e) {
      return e.id === d.node02
    }).attr("cy")
  })
  .attr("stroke", "gray");
  
circles.raise();
<script src="https://d3js.org/d3.v4.min.js"></script>

Upvotes: 1

Related Questions