The legend for proportional circles sizes is drawn automatically.
Reprojectiong on the fly from WGS84 to the newly available AirOcean (Dymaxion projection) in D3v5.
Example data: number of political reports sent by Swiss embasies to Bern in all languages and in French specifically betwee 1920 annd 1960.
Running D3 version of this map is available here.
<!DOCTYPE html> <meta charset="utf-8"> <style> .states1920 { stroke: white; stroke-width: 0.5; fill: lightgrey; } .states1945 { stroke: white; stroke-width: 2; stroke-opacity:0.5; fill: none; } .citiesall { fill:white; stroke:black; fill-opacity: 0.5; stroke-opacity: 0.5; } .citiesselected { fill:black; stroke:white; } .legend{ font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif; font-size: 1.3em; } .legendtitle{ font-variant: small-caps; font-weight: bold; } .legendscale{ font-size: 0.8em; } </style> <svg width="1500" height="900"></svg> <script src="d3/d3.v5.min.js"></script> <script src="d3/d3-geo.v1.min.js"></script> <script src="d3/d3-geo-projection.v2.min.js"></script> <script src="d3/d3-geo-polygon.min.js"></script> <script> var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height"); var region = "world"; // can be world or europe. var legendtranslate = "translate(1000,800)"; // positioning the legend if (region == "europe") { var projection = d3.geoPeirceQuincuncial() .scale(1300) .translate([0.35*width, -0.35*height]) .precision(0.1); legendtranslate = "translate(100,350)"; } else { var projection = d3.geoAirocean() .scale(90) .translate([0.5*width,0.5*height]) .precision(0.1); } var path = d3.geoPath() .projection(projection); var scaler = 2; Promise.all([ d3.json('world_1920.geojson'), d3.json('world_1945.geojson'), d3.json('citiesallreports.geojson'), d3.json('citiesselected.geojson') ]).then(([states1920,states1945,citiesall,citiesselected]) => { svg.append("g") .attr("class", "states1920") .selectAll("path") .data(states1920.features) .enter().append("path") .attr("d", path) ; svg.append("g") .attr("class", "states1945") .selectAll("path") .data(states1945.features) .enter().append("path") .attr("d", path) ; svg.append("g") .attr("class", "citiesall") .selectAll("circle") .data(citiesall.features.sort(function(a, b) { return b.properties.count - a.properties.count; })) .enter().append("circle") .attr("cx", function (d) { return projection(d.geometry.coordinates)[0]; }) .attr("cy", function (d) { return projection(d.geometry.coordinates)[1]; }) .attr("r", function (d) { return Math.sqrt(d.properties.count) /scaler; }) ; svg.append("g") .attr("class", "citiesselected") .selectAll("circle") .data(citiesselected.features.sort(function(a, b) { return b.properties.count - a.properties.count; })) .enter().append("circle") .attr("cx", function (d) { return projection(d.geometry.coordinates)[0]; }) .attr("cy", function (d) { return projection(d.geometry.coordinates)[1]; }) .attr("r", function (d) { return Math.sqrt(d.properties.count) / scaler; }) ; // add a legend ----- // add maximum circle sizes maxcitall = citiesall.features.sort(function(a, b) { return b.properties.count - a.properties.count; })[0].properties.count; maxcitsel = citiesselected.features.sort(function(a, b) { return b.properties.count - a.properties.count; })[0].properties.count; rmaxcitall = Math.sqrt(maxcitall)/scaler; // prepare circle radidus rmaxcitsel = Math.sqrt(maxcitsel)/scaler; var legend = svg.append("g").attr("class","legend").attr("transform",legendtranslate); legend.append("circle").attr("class","citiesall").attr("r",rmaxcitall); // the center of this one one serves as a reference point for the other elements. This center is at position 0,0 with respect to the g element, which we have translated legend.append("circle").attr("class","citiesall").attr("r",Math.sqrt(1000)/scaler) .attr("cy",-(rmaxcitall-Math.sqrt(1000)/scaler)) ; legend.append("text").text("number of sent reports per city") .attr("class","legendtitle") .attr("x",-rmaxcitall) .attr("y",-rmaxcitall-36) ; legend.append("text").text("All languages") .attr("x",-rmaxcitall) .attr("y",-rmaxcitall-12) ; legend.append("text").text("French") .attr("x",-(rmaxcitsel) + 200) .attr("y",-rmaxcitall-12) ; legend.append("circle").attr("class","citiesselected").attr("r",rmaxcitsel) .attr("cx",200) .attr("cy",-(rmaxcitall-rmaxcitsel)) ; legend.append("circle").attr("class","citiesselected").attr("r",Math.sqrt(1000)/scaler) .attr("cx",200) .attr("cy",-(rmaxcitall-Math.sqrt(1000)/scaler)) ; legend.append("text").text("1000").attr("class","legendscale") .attr("x",rmaxcitall+35) .attr("y",-rmaxcitall+ Math.sqrt(1000)/scaler*2) // *2 because interested in diameter not radius, here ; legend.append("text").text(maxcitsel).attr("class","legendscale") .attr("x",rmaxcitall+35) .attr("y",-rmaxcitall+rmaxcitsel*2) ; legend.append("text").text(maxcitall).attr("class","legendscale") .attr("x",rmaxcitall+35) .attr("y",rmaxcitall) ; }); </script>
Comments are closed.