Circles in Map Displayed Incorrect Location in D3 V4

Your US json is already projected, and to show it you use a null projection:

var path = d3.geoPath()
             //.projection(projection)

Without defining a projection, your topojson/geojson coordinates will be translated to straight pixel coordinates. It just so happens that this particular topojson file has pixel coordinates that are within [0,0] and [960,600], almost the same size as a default bl.ock view. Without knowing the projection used too create that file you cannot replicated that projection to align geographic features to your data. Unless you place your features with pixel values directly and skip the projection altogether (not useful for points not near identifiable landmarks or where precision matters).

Your US topojson features disappear when projecting with a geoUsaAlbers() because you are taking pixel coordinates on a plane and transforming them to svg coordinates as though they were points on a three dimensional globe (d3 projections expect latitude longitude pairs).

Instead, use a topojson or geojson that is unprojected. That is to say it contains latitude/longitude pairs and project that data along with your points. See this bl.ock for an example with unprojected (lat/long pairs) json for the US using your code (but assigning a projection to path).

To check if you have latitude/longitude pairs you can view the geometry of these features in a geojson file easily and see if the values are valid long, lat points. For topojson, the topojson library converts features to geojson, so you can view the geometries after this conversion.

Here’s an unprojected topojson of the US: https://bl.ocks.org/mbostock/raw/4090846/us.json


Let’s say you really wanted to use the same topojson file though, well we can probably deduce the projection it uses. First, I’ll show the difference between your projected points (by using an unprojected outline of the US) and the already projected topojson (the unprojected topojson is projected with d3.geoAlbersUsa() and the projected with a null projection):

enter image description here

Chances are the projection d3.geoAlbersUsa is optimized for a bl.ocks.org default viewport, 960×500. The unprojected dataset has a bounding box of roughly 960×600, so perhaps if we increase the scale by a factor of 600/500 and adjust the translate we can align our features in an svg that is 960×600:

var projection = d3.geoAlbersUsa();
var scale = projection.scale() * 600 / 500;
projection.scale(scale).translate([960/2,600/2])
var projectedPath = d3.geoPath().projection(projection);

And, this appears to align fairly well, I can’t see the difference between the two:

enter image description here

Here’s a block showing the aligned features.

But as I mention in the comments, even if you can align the features:
any zoom or centering would be problematic as you need to use a geoTransform on already projected data but a geoProjection on the raw geographic data. Using all (uniformly) projected data or all unprojected data makes life simpler.

Leave a Comment