We’ve done maps based on points before, now it’s time to stretch out d3 projection skills a little bit further!
Data format: GeoJSON
Generally we use d3.csv to read in our data, because… our data is a CSV, of course. This time we’re going to be using JSON, and (surprise!) d3 supports that with d3.json.
If you look at the console, you can see it has two keys:
type, which is set to "FeatureCollection"
features, which is an array with around 3000… things in it.
Each of those features has its own attributes, and some of those attributes have their own sub-attributes, and who knows, maybe it goes on forever and ever? Don’t sweat it, though, we’ve got this covered!
This is a specific kind of JSON called GeoJSON. It’s the exact same thing as JSON, just formatted in a specific way. For example, from http://geojson.org/:
Every single GeoJSON document will be formatted in the exact(-ish) same way, typically a FeatureCollection with a bunch of Features inside of it, and each of those features has geometry (the geography of the feature) and properties (the data attached to the feature). What we have now is
FeatureCollection of all of the counties in the USA
Each county is a Feature
Each county’s boundaries is inside of geometry, usually a MultiPolygon
Each country’s data set - its name, area, etc - is stored inside of properties
It might be easier if you take a little while to play around with creating your own GeoJSON! I highly highly recommend hopping on over http://geojson.io/, which allows you to build your own GeoJSON.
Back to our code
Pulling out the counties
First, let’s take out all of the counties into their own variable. Since we have a FeatureCollection, all of the counties are inside of the features key of our data.
Building our chart space
Nothing weird here, just making an svg and putting a g inside of it (we don’t have to use a g since we don’t have margins, but I think it’s good practice.)
Creating our projection and adding our shapes
You can’t have a map without a projection! Since this is the USA, we’ll stick with d3.geo.albersUSA.
Last time we made a map we used circle to draw points, but how do we draw shapes? Remember when we tried to draw a line on a graph and accidentally drew these really weird ugly shapes instead? It’s the same thing!
In SVG, lines (with multiple points in them) and shapes are the same thing, shapes just happen to be filled in. This means we’ll use path to draw our shapes.
…but last time we made a line with path, we had to set the d attribute to give it a path. We had a d3.geo.line thingie help us plot the x and y. You’ll probably remember with an example!
But times have changed! We’re using a projection now, which means we don’t have an x-scale and y-scale anymore, we have some weird convoluted system instead. When we were plotting circles we used something like this:
BUT WORRY NO MORE! When we’re mapping with lines, d3 takes care of it all behind the scenes. It has a built-in projection helper for lines that is confusingly called path. Instead of muddling through like we did with circles, it’s so easy we might just die.
Putting it together
I know it’s been a lot! We just haven’t had enough to draw an entire page yet. Let’s do that now!
AWESOME! And we didn’t even do much at all, really. That’s like ten lines of code after we create the SVG!
Coloring the map
Now we all know we could use .style('fill', '#ff0000') to make the map red. But how do you change the color based on some value? We could always use console.log inside of a .style call, like so:
It gives us a type, some properties and geometry.
Where we could usually do something like d['NAME'], when you work with GeoJSON you always always always need to look inside of properties. Always always always (usually). You will forget this, but try not to. console.log will help you realize what you’ve done, but it’s always best to be prepared. Let’s look a everyone’s Census land area.
Hmmm. That’s… a lot of numbers? If we’re going to build a scale, we’ll want to lean on our old friend d3.max.
Remember, it’s always inside of ['properties']! Then we’ll make an appropriate scale using this data.
And plop that into the .style call
And we should be good to go! Let’s put it all together and see if it works.
Ah, that’s… pretty useless. You can see that Alaska has some big counties and that the projection is making them nice and small, but it seems kind of useless.
The right thing to do in this case is (probably) to make a histogram and figure out what the best ways to cut that up. But hey, instead of doing that, let’s just try a bunch of different color scales!
Middle values
What if instead of saying “these are big”, instead we wanted to say “these are medium and these are big and these are small”? We might have blue be 0, beige be the median, and red be the largest.
Question: But how?
Answer: Your friend d3.max has a friend named d3.median that you can use with d3.scale.linear().
And when you’re making a color scale, you can pass multiple ranges. You can say zero to the median is blue to beige, and the median to max is beige to red. You do this like so:
Now that you’ve seen that mixing up the color scale a little can tell a whole different story, check out the same map colored many many different ways at color scale examples.
Want to hear when I release new things? My infrequent and sporadic newsletter can help with that.