2

I am a newbie, attempting to copy someone else's choropleth code and use my data.

My data matches their data structure and I can get the correct data to console.log() and my tooltips display correct data.

But my map is just a big block of colour with no paths.

Here is a codepen, but this is the code that renders the map features:

var path = d3.geo.path();

svg.append("g")
    .attr("class", "county")
    .selectAll("path")
    .data(topojson.feature(us, us.objects.counties).features)
    .enter().append("path")
    .attr("d", path)
    .style("fill", function (d) {
      return color(pairFipsWithId[d.id]);
    })

The result looks like this:

enter image description here

Andrew Reid
  • 37,021
  • 7
  • 64
  • 83
nerz
  • 337
  • 1
  • 5
  • 13

1 Answers1

1

⚠️This question and answer both use d3v3 - d3v4+ geo paths are slightly different, see this question/answer for d3v4+.

If you are making a D3 choropleth, you should be looking for a recent version of D3 - d3v3 is a bit dated now. However, as v3 has some differences, this isn't quite a duplicate of this question, but the problem is the same:

  • The example map you use has unprojected geographic data
  • Your geographic data is projected.

In other words, your example's geographic data uses a 3 dimensional coordinate system measured in degrees latitude and longitude, while your geographic data uses a coordinate system where the units are pixels. But, you don't specify this change and D3 does not know to correct for it.

In D3v3, the default projection for a d3.geo.path() is d3.geo.albersUsa(), all D3 projections assume your data is recorded in latitudes and longitudes, otherwise we would need to specify an additional parameter to projections to indicate what coordinate space the input data uses.

A sign that your data is already projected can come from mapshaper.org, if you drag your topojson into the window your map is upside down. Why? Geographic coordinates increase as one moves north (typically up) while pixel coordinates increase as one moves down. This is your data in mapshaper.org:

enter image description here

We cannot "unproject" the data as we don't know what projection was used to create it. But we could assign a null projection to the geo.path:

var path = d3.geo.path().projection(null)

The null projection simply takes each coordinate in the data and converts it to a pixel coordinate with no transform - input values are treated as pixel values. As this map was designed for a web map it doesn't need any scaling or centering (depending on the size of your SVG).

Here's an updated codepen.

In d3v4+, the default projection of a geoPath is a null projection off the bat, it also comes with selection.raise() and selection.lower() methods that can simplify your code a bit, as well as better options for fitting any dataset to a SVG/Canvas of a given size. Here's a d3v4 codePen with a few modifications, d3v5 requires a bit more in updating d3.json

Andrew Reid
  • 37,021
  • 7
  • 64
  • 83
  • Thank you Andrew for a very comprehensive answer. There is no way I would have figured that out on my own. I don't fully understand, but it's given me a good idea of where I was going wrong. There are many ways to do the same thing and I guess samples need to be backed up by researching what the methods do. I'm lacking some basic understanding with d3. Again...thank you. – nerz Jul 05 '19 at 16:41
  • 1
    My pleasure. It might be useful: I do have a more in depth answer on choropleths and d3 [here](https://stackoverflow.com/q/42616525/7106086), which also speaks a bit to how d3 is doing things, the data join, etc. – Andrew Reid Jul 05 '19 at 16:43