Skip to content

Instantly share code, notes, and snippets.

@clhenrick
Last active March 16, 2022 06:12
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save clhenrick/a5972639e5f3032ac4f8e1c75d221505 to your computer and use it in GitHub Desktop.
Save clhenrick/a5972639e5f3032ac4f8e1c75d221505 to your computer and use it in GitHub Desktop.
Aligning GeoJSON data with us-atlas TopoJSON

This is a demonstartion of how to align arbitrary GeoJSON data to the us-atlas topojson data.

It's important to note that the TopoJSON from us-atlas has it's map projection, (d3.geoAlbersUsa), built into it. In other words, it is considered "projected" geographic data.

This is an important distinction from GeoJSON data which is most typically stored in the unprojected Coordinate Reference System WGS84, also commonly referred to as "lat, lon" (though coordinates are most often stored in the order longitude, latitude).

In order to properly align arbitrary GeoJSON data with us-atlas, we need to properly set the projection's scale and translate attributes to those used by us-atlas, which can be found in its prepublish script:

var projection = d3.geoAlbersUsa().scale(1280).translate([480, 300]);

This will give us correct SVG x, y coordinates from lon, lat coordinates. For instance:

projection([-122.41, 37.76]) 

// returns
Array [ 34.37093520874129, 257.47410484805755 ]

Otherwise, using d3.geoAlbersUsa alone will result in the GeoJSON data being mis-aligned with the map.

<!DOCTYPE html>
<style>
svg { border: 1px solid #333; }
</style>
<svg width="960" height="600" fill="none" stroke="#000" stroke-linejoin="round" stroke-linecap="round"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://unpkg.com/topojson-client@3"></script>
<script>
var svg = d3.select("svg");
var path = d3.geoPath();
// define a projection function that matches the us-atlas projected topojson data
var projection = d3.geoAlbersUsa().scale(1280).translate([480, 300]);
d3.json("https://gist.githubusercontent.com/clhenrick/0323450eb5820ca49436adeb4428a239/raw/63ef6a2bc968779ff6a3e5f96583558196ac7fbb/ne_10m_populated_places_simple_filtered.json", function (error, places) {
if (error) throw error;
d3.json("https://unpkg.com/us-atlas@1/us/10m.json", function(error, us) {
if (error) throw error;
svg.append("path")
.attr("stroke-width", 0.5)
.attr("d", path(topojson.mesh(us, us.objects.states, function(a, b) { return a !== b; })));
svg.append("path")
.attr("d", path(topojson.feature(us, us.objects.nation)));
// add geojson data
svg.selectAll("circle")
.data(places.features)
.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", 5)
.attr("fill", "red");
});
});
</script>
@Taulantvokshi
Copy link

Good work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment