3

I'm starting to study D3 in order to create a choropleth/heatmap with filter by year.

Problem:

I would like to display this topojson file. I've tried to adapt Mike Bostock's topojson example here. However, when I adapt the example for my topojson nothing displays and no errors are shown in the console.

My code looks like this:

var svg = d3.select("svg");
var path = d3.geoPath();
d3.json("aisp.topojson", function(error, aisp) {
  if (error) throw error;

svg.append("g")
  .attr("class", "states")
.selectAll("path")
 .data(topojson.feature(aisp, aisp.objects.convert).features)
.enter().append("path")
.attr("d", path);


svg.append("path")
  .attr("class", "state-borders")
  .attr("d", path(topojson.mesh(aisp, aisp.objects.convert, function(a, b) { return a !== b; })));
}); 
Andrew Reid
  • 37,021
  • 7
  • 64
  • 83
abaporu
  • 320
  • 2
  • 12
  • Look at the console. Your topojson has a problem, it ends like this: `...[-10,-21],[-6,-22],[-9` – Gerardo Furtado Jan 23 '18 at 23:34
  • The error comes from this code: `aisp.convert` - this is undefined, you want `aisp.objects.convert` (when appending the mesh, not the initial paths). (the topojson checked out when I looked at it, however, I believe you'll have a different question once the error goes away, "where are my features?") – Andrew Reid Jan 23 '18 at 23:55
  • @AndrewReid The topojson OP linked has an unexpected end, don't it? – Gerardo Furtado Jan 24 '18 at 00:01
  • @GerardoFurtado, not when I opened it, loaded fine into d3 and displayed on github, ending I see is: `...1.3:CRS84"}}}`, I find that gitHub sometimes truncates long geo/topojson for some reason - has caused lots of grief for me previously. – Andrew Reid Jan 24 '18 at 00:02
  • 1
    Yes, trying for the 10th time I see the correct end. It was probably a connection timeout at my side... or a GitHub issue, as you said. – Gerardo Furtado Jan 24 '18 at 00:03
  • @AndrewReid thanks! you're right.. now I'm trying to figure out where my features. Is it a projection issue? Should I edit the post or open a new question here? – abaporu Jan 24 '18 at 00:09
  • @abitporu, If you don't mind, I have edited the question - it could be a good canonical question for this problem which comes up in various flavors relatively often, generally citing the same example (and given that the first issue was just missing a property name, wouldn't waste a question) – Andrew Reid Jan 24 '18 at 00:35

1 Answers1

5

Problem

Using this block as an example can be problematic because it does not use a projection. The example uses a preprojected topojson that has its coordinates in pixel coordinate space - it is designed to be shown over a 900 x 600 pixel window and the range of coordinate values in the input file are within the bounding box of [0,0] and [900,600]. For this reason, the example does not use a geographic projection.

Geographic coordinates will not fall entirely in this range.

Why Does Nothing Draw?

Your topojson features, unlike the example, contain geographic coordinates - latitudes and longitudes.

To project geographic features in d3 or any other framework or program, a projection must be applied to convert geographic coordinates in three dimensional coordinate space to planar Cartesian coordinates fit to be displayed on a two dimensional svg or canvas grid.

You are not applying a necessary projection to your features. When you use a geoPath you generally need to specify a geoProjection:

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

However, you don't use a projection, so d3 defaults to a null projection. For each coordinate in your topojson/geojson, the x and y values of the input are taken as pixel coordinates, no transform/translate/scaling is done.

Since your features are located in the Western hemisphere, the x (longitude) values are negative. Pixels with negative x values are located off screen to the left.

Values in the Southern hemisphere have negative values, so they too will be drawn off screen. In this case above the svg or canvas - because y values start at zero at the top of the screen and increase as one moves down.

Lastly, If you had any features in the North-Eastern quadrant of the globe, they would appear as their coordinates would be positive (assuming your svg was at 90 pixels high and 180 pixels wide). But, they would be upside down, as y values increase as one moves "up" a map, but in svg/canvas coordinate space they decrease as one moves "up" a map.

Fixing the Issue

You will need to use a projection. The most basic setup might be using a simple projection like a Mercator and using fitSize or fitExtent to automatically scale and center the features you want to show. To do so you could use something like:

var projection = d3.geoMercator();
var path = d3.geoPath().projection(projection);

// once topojson is loaded:
projection.fitSize([width,height],geojson object);

How do you get the geojson? You already are:

topojson.feature(aisp, aisp.objects.convert)  // convert topojson to geojson.

You need to pass the geojson object, not the array of features it contains, hence why we wouldn't use topojson.feature(aisp, aisp.objects.convert).features with .fitSize.

FitSize takes a width and height and sets the projection's scale and translate to appropriate values. FitExtent takes two points marking the top left and bottom right of a bounding box for the features: projection.fitExtent([[x1,y1],[x2,y2]],geojson);

This approach doesn't set the more complex parameters of the projection such as rotation or for conical projections such as an Albers, parallels, but it is sufficient in many cases.

Example

Here's an example of your map with fitSize (I changed the file name).

Andrew Reid
  • 37,021
  • 7
  • 64
  • 83
  • Upvoted... now guess the state and the country (without the GitHub help). – Gerardo Furtado Jan 24 '18 at 00:30
  • I know the country - and I know why you would know. But the state? Would not have guessed it probably given that I would have associated it with a city rather than a state. – Andrew Reid Jan 24 '18 at 00:33
  • Rio de Janeiro. The state's name is the same of the city (just like New York state and New York city - however, unlike Rio, New York's capital is not New York). – Gerardo Furtado Jan 24 '18 at 00:34
  • Yeah, but that's those names are the exception. The only possible name that came to (after a while) mind was Espirito Santo because of the Fundao dam disaster, which has been fairly topical at work. – Andrew Reid Jan 24 '18 at 00:41
  • Perfect, thanks @AndrewReid for the explanation and Geraldo for following the question :) – abaporu Jan 24 '18 at 01:08