1

I want to create a US map based on county data. I'm using this JSON topology data to create the graph: https://cdn.freecodecamp.org/testable-projects-fcc/data/choropleth_map/counties.json

In the first step, I created the map like this, and it works fine:

var path = d3.geoPath();

svgContainer.selectAll("path")
  .data(topojson.feature(countyData, countyData.objects.counties).features)
  .enter()
  .append("path")
  .attr("d", path)

Picture: US map renders OK but too large

However, it is too large for my purpose so I'm trying to scale it down. I tried projections which I saw in several other projects (for example here: https://www.d3-graph-gallery.com/graph/choropleth_basic.html). Unfortunately it just renders a black rectangle. I also tried geoAlbersUsa() and some other projections, but it did not help. How can I get the map data to scale?

var projection = d3.geoAlbersUsa()  // geoMercator() also does not work
  .scale(200)
  .translate([width / 2, height / 2]);

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

svgContainer.selectAll("path")
  .data(topojson.feature(countyData, countyData.objects.counties).features)
  .enter()
  .append("path")
  .attr("d", path)

Picture: projection renders black rectangle

What am I doing wrong here?

Mia Temma
  • 53
  • 9

1 Answers1

1

Everything looks good in the second block of code (using d3.geoAlbersUSA()) except I think you are zoomed in too close with .scale(200) and only seeing the middle of a county. As explained in this post, if you zoom out with smaller scale value you may start to see more of your map.(What does it mean to scale a projection in d3?) You may be better off using .fitSize() instead of .scale since you seem to be trying to fit the whole topojson data set inside an area rather than zooming into part of it. Updated your example below using a variable margin.

var margin = 20; //amount of whitespace you want around the map
 var projection = d3.geoAlbersUsa()  
  .translate([width / 2, height / 2]);

var path = d3.geoPath().projection(projection);
var countiesFeatureCollection = topojson.feature(countyData, countyData.objects.counties);
//make the map projection fit into size of screen minus margin on all sides
projection.fitSize([width - margin*2, height - margin*2], countiesFeatureCollection);


svgContainer.selectAll("path")
  .data(countiesFeatureCollection.features)
  .enter()
  .append("path")
  .attr("d", path)
Katherine
  • 98
  • 6
  • For others coming here, this solution is assuming you are using at least d3 v4 as that is the version in the example OP linked to. fitSize() is not available in older version of D3.js – Katherine Mar 09 '21 at 07:38
  • Hello Katherine, thanks a lot for your reply! It helped me to get some basic understanding how the projection works. You are right that it is too much zoomed in, so the "rectangle" is actually only showing a very very tiny bit of the map. However, your proposal still renders the same result, as well as to do "scale" with a smaller number. I wonder if the geoAlbersUsa()-Projection does not work with the provided dataset..? Is it possible to scale without defined projection method? Or is there something like a "neutral" projection? – Mia Temma Mar 09 '21 at 22:22
  • Possibly the dataset in your countyData variable is in a different format from the one I used for a minimal working example. You could compare to the formats of projected and unprojected files at https://github.com/topojson/us-atlas. I tested my code with a file at https://raw.githubusercontent.com/gist/mbostock/4090846/raw/07e73f3c2d21558489604a0bc434b3a5cf41a867/us.json. – Katherine Mar 10 '21 at 02:02