Plot Points Based on Distances Between Them
3 min read

Plot Points Based on Distances Between Them

Plot Points Based on Distances Between Them

My problem this days is:

I need to provide a drawing of trees on my plot of land in order to see which can be spared when building the house.

The easiest way to do this is to measure the distance between the said trees, add some basic coordinates (to place them within the plot of land) and build a drawing. Initially I thought of building the algorithm myself (or even drawing them by hand), but I found something online, based on d3.js, namely a force-directed graph.

I have adjusted the source code to contain a single group and a dummy node named "0". Given that I wanted a quick run, I only created an index.html file with the following layout:

  • Header and style

    <!DOCTYPE html>
    <meta charset="utf-8" />
    <style>
      .node {
        stroke: #fff;
        stroke-width: 1.5px;
      }
    
      .link {
        stroke: #999;
        stroke-opacity: 0.6;
      }
    </style>
    
  • The document start tags:

    <body>
    <script src="d3.min.js"></script>
    <script>
    
  • The graph (not complete though):

    var graph = {
      nodes: [
        { name: '0', group: 0 },
        { name: '1', group: 1 },
        { name: '2', group: 1 },
        { name: '3', group: 1 },
        { name: '4', group: 1 },
        { name: '5', group: 1 },
        { name: '6', group: 1 },
        { name: '7', group: 1 },
        { name: '8', group: 1 },
        { name: '9', group: 1 },
        { name: '10', group: 1 },
        { name: '11', group: 1 },
        { name: '12', group: 1 },
        { name: '13', group: 1 },
        { name: '14', group: 1 },
        { name: '15', group: 1 },
        { name: '16', group: 1 },
        { name: '17', group: 1 },
        { name: '18', group: 1 },
        { name: '19', group: 1 },
        { name: '20', group: 1 }
      ],
      links: [
        { source: 1, target: 2, value: 4.23 },
        { source: 2, target: 3, value: 3.54 },
        { source: 2, target: 4, value: 6.31 },
        { source: 2, target: 5, value: 5.38 },
        { source: 2, target: 6, value: 2.96 },
        { source: 5, target: 6, value: 2.96 },
        { source: 5, target: 7, value: 1.6 },
        { source: 6, target: 7, value: 4.49 },
        { source: 6, target: 8, value: 10.31 },
        { source: 5, target: 8, value: 10.88 },
        { source: 2, target: 9, value: 6.23 },
        { source: 8, target: 9, value: 7.09 },
        { source: 9, target: 10, value: 9.05 },
        { source: 10, target: 11, value: 4.52 },
        { source: 10, target: 12, value: 7.55 },
        { source: 10, target: 13, value: 2.84 },
        { source: 11, target: 12, value: 4.37 },
        { source: 12, target: 13, value: 5.99 },
        { source: 13, target: 14, value: 8.23 },
        { source: 13, target: 15, value: 5.56 },
        { source: 15, target: 16, value: 3.98 },
        { source: 15, target: 17, value: 12.45 },
        { source: 15, target: 18, value: 7.04 },
        { source: 14, target: 18, value: 8.23 },
        { source: 14, target: 19, value: 13.62 },
        { source: 13, target: 20, value: 11.55 },
        { source: 19, target: 20, value: 7.9 }
      ]
    }
    
  • The directed graph drawing:

    var width = 960,
    height = 500;
    
    var color = d3.scale.category20();
    
    var force = d3.layout.force()
    .charge(-120)
    .linkDistance(function(link, index) { return link.value \* 2; })
    .size([width, height]);
    
    var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);
    
    force
    .nodes(graph.nodes)
    .links(graph.links)
    .start();
    
    var link = svg.selectAll(".link")
    .data(graph.links)
    .enter().append("line")
    .attr("class", "link")
    .style("stroke-width", function(d) { return Math.sqrt(d.value); });
    
    var node = svg.selectAll(".node")
    .data(graph.nodes)
    .enter().append("circle")
    .attr("class", "node")
    .attr("r", 5)
    .style("fill", function(d) { return color(d.group); })
    .call(force.drag);
    
    node.append("title")
    .text(function(d) { return d.name; });
    
    force.on("tick", function() {
    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; });
    
    node.attr("cx", function(d) { return d.x; })
    .attr("cy", function(d) { return d.y; });
    });
    
  • The closure tags:

    </script>
    </body>
    

This HTML code will generate the layout with distances between trees (note the linkDistance() function call above and this SO answer).

HTH,