1

I'm trying to load my topojson file of the map of ontario using d3, but all I get is a bunch of random lines, just like Random lines when loading a TopoJSON file in D3.

My file is using WGS84 so that's not the issue either. What am I doing wrong? Js code below.

var width = 960, height = 700;

var svg = d3.select('#map').append('svg')
  .attr('width', width)
  .attr('height', height)

d3.json('CensusSubDiv.json', function(error, CensusSubDiv) {
  if (error) return console.error(error);



  svg.append('path')
  .datum(topojson.feature(CensusSubDiv, CensusSubDiv.objects.CensusSubDivision))
  .attr('d', d3.geo.path().projection(d3.geo.mercator()))
  .attr('id', 'ont')
;
});
user3611
  • 129
  • 1
  • 8
  • Can you provide a link to the topojson file? This is almost certainly a projection issue, which requires a look at the topojson, or info on where it came from or how it was made. – Andrew Reid Mar 14 '18 at 18:58
  • Sure, here: http://blockbuilder.org/smokbel/aeca7a2fc3e03645b4421d516e9bd947 and in terms of how it was made: I downloaded the shapefile from arccatalogue, where it was wgs84.. but then i uploaded it to mapshaper.org to save it as a topojson file, then used that. not sure if the projection changed after that but it was originally wgs84 – user3611 Mar 14 '18 at 21:35
  • Your data might use the WGS84 datum, but it is projected, here's an example coordinate if you convert it to geojson: `[ -8807513.029453829,5613652.854071041]`. This isn't a long/lat pair. You could use the file as is if you don't need to overlay other geographic features with some modifications to your path, if this is. But, if you need to overlay other geographic features, you'll need to know the projection the data uses (if you made this with a shapefile, then the prj file will help). – Andrew Reid Mar 14 '18 at 21:40
  • Mapshaper won't change the projection, though you can "project" the data to be projectionless (lat,long) with `proj WGS84` in the command line on mapshaper. – Andrew Reid Mar 14 '18 at 21:41
  • thank you - i just tried `proj wgs84` in the command line in mapshaper and the geojson coordinates look the same. is this normal? – user3611 Mar 14 '18 at 21:50
  • You'll need to ensure that you drag in the .prj file of the shapefile along with the .shp and .dbf files. Export to geojson to see plain text coordinates. – Andrew Reid Mar 14 '18 at 22:05

1 Answers1

0

So, as I mentioned in the comments, your data may use WGS84 as a datum, but D3 requires WGS84 to be used as a "projection" (d3 requires latitude and longitude, which represent points on a three dimensional globe, and thus are actually unprojected, hence my quotes). Projected data, consequently, is labelled with WGS84 sometimes as well as other identifiers.

The good news is you can display projected data fairly easily - the better news is that this is faster. Instead of doing three dimensional math, we just transform and scale the data before plotting it. The bad news is that this works easiest with d3 v4 (which my example uses, it only changes a few points: eg: d3.geo.path -> d3.geoPath, d3.geo.projection -> d3.geoProjection, etc).

As your data is already projected, we can use d3.geoIdentity which allows us to use the projection.fitSize() (which modifies scale and translate) method but otherwise doesn't project the data. FitSize takes an array for the width/height of the display area and a geojson object:

projection.fitSize([width,height],geojsonObject) 

fitSize is not part of d3v3, but we're on d3v5, so updating isn't a bad thing, projection.fitExtent allows for margins

As in SVG coordinate space, Y values start at 0 at the top of the screen and increase as one moves down, and in most projected coordinate spaces, Y values start at the bottom of the map and increase as one moves north, we also need to flip the identity on the y axis:

var projection = d3.geoIdentity()
   .reflectY(true)
   .fitSize([width,height],geojsonObject) 

This allows us to display the data fairly easily. See this block for your data with the above noted changes.

But, here's the caveat, you have data that is already projected, if you don't know how that data was projected, you can't align other geographic data that is unprojected or otherwise projected: you can't project a point with given longitude latitude because you don't know how to project it in the same manner as your already projected data.

This might not be a concern, for example in a choropleth perhaps you only need the outline of the census subdivisions. But if you wanted to place cities on top of the map, you'd face some difficulties if the coordinates for those cities weren't already projected in the same manner as your census data.

If you wanted to overlay other geographic data (unprojected data) over Ontario, then you will need to unproject your data. In mapshaper, when you initially import the data into the window (ensuring you drag the .prj file too - otherwise mapshaper won't know what projection to reproject the data from), you can open the console and type proj WGS84, this should give you coordinates that are in degrees (though the topojson will still have encoded integer coordinates, the coordinates are stored in plain text if exporting to geojson). Of course, you'll need to use more typical projection, such as a d3.geoMercator() again if you chose to unproject your data.

Andrew Reid
  • 30,848
  • 7
  • 44
  • 62
  • Hey Andrew, thank you so much for your help and detailed explanation. It is a lot clearer to me now and I finally got it to draw. I do not believe I'll be needing to add any other demographic data, however, ill probably link other subdivision data (just csv's or something along those lines) to create a choropleth/interactive map. – user3611 Mar 15 '18 at 16:33
  • No problem, glad to help. – Andrew Reid Mar 15 '18 at 16:57