Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

d3.js: Drawing arcs between two points on map from file

Tags:

d3.js

I am new to d3.js and am trying something simple. I have drawn a world map that reads in file1 and file2. file2 lists airports by an indexID, lat, and lon. file1 pairs the airports by their indexID. I want to draw an arc, line, or anything to connect them. The idea was to produce something like this: http://mbostock.github.io/d3/talk/20111116/airports.html with a different data set but this example was too hard to follow.

The code below correctly draws the map and plots circles for the airports, but remains to be seen how to connect them.

<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script type="text/javascript" src="d3/d3.v3.js"></script>
<script src="js/topojson.v0.min.js"></script>
<script>
    var width = 2000, height = 2000;
    var projection = d3.geo.mercator().center([0, 5]).scale(100).rotate([0, 0]);
    var svg = d3.select("body").append("svg").attr("width", width).attr("height", height);
    var path = d3.geo.path().projection(projection);
    var g = svg.append("g");

    d3.json("json/world-110m2.json", function(error, topology) {// load and display the World
        g.selectAll("path").data(topojson.object(topology, topology.objects.countries).geometries).enter().append("path").attr("d", path)
    });

    d3.csv("file1", function(flights) { //Attempt to draw arcs
        var linksByOrigin = {}, countByAirport = {}, locationByAirport = {}, positions = [];

        var arc = d3.geo.greatArc().source(function(d) {
            return locationByAirport[d.source];
        }).target(function(d) {
            return locationByAirport[d.target];
        });

        flights.forEach(function(flight) {
            var origin = flight.origin, destination = flight.destination, links = linksByOrigin[origin] || (linksByOrigin[origin] = []);
            links.push({
                source : origin,
                target : destination
            });
            countByAirport[origin] = (countByAirport[origin] || 0) + 1;
            countByAirport[destination] = (countByAirport[destination] || 0) + 1;
        });

        d3.csv("file2", function(error, data) {// read in and plot the circles
            g.selectAll(".blue.circle").data(data).enter().append("circle").attr("class", "blue circle").attr("cx", function(d) {
                return projection([d.lon, d.lat])[0];
            }).attr("cy", function(d) {
                return projection([d.lon, d.lat])[1];
            });

            g.selectAll("path.arc").data(function(d) {
                return linksByOrigin[data.ctuid] || [];
            }).enter().append("svg:path").attr("class", "arc").attr("d", function(d) {
                return path(arc(d));
            });
        });
    });
</script>
</body>
</html>

I am new to this so the code may be sloppy, but any hints about connecting points pulled from a CSV would be greatly appreciated. Thank you!

like image 606
user2494663 Avatar asked Jan 13 '23 03:01

user2494663


1 Answers

To draw an arc between points why not use a path with arc directive(A). I too tried greatArc, but din't work. But found an alternate from this discussion and the alternate is given below:

 path.attr("d", function(d) {
    var dx = d.target.x - d.source.x,
        dy = d.target.y - d.source.y,
        dr = Math.sqrt(dx * dx + dy * dy);
    return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr +
" 0 0,1 " + d.target.x + "," + d.target.y;
  });

Replace path(arc(d)) with the above snippet and replace the x and y values according to your values. This worked like charm for me. Hope this helps.

like image 104
Jebin Avatar answered Feb 12 '23 13:02

Jebin