D3 Map
From charlesreid1
Installing
First step was prerequisites.
Prerequisites
I had to install GDAL (software for converting different geographic formats) and NPM (node package manager):
brew install gdal brew install npm
Next, I used npm to install TopoJSON:
npm -g topojson
Then I checked that the installations went ok with:
which ogr2ogr which topojson
Converting
GeoJson to TopoJson
To convert a GeoJson to a TopoJson and preserve properties:
topojson in.geojson -o out.json -p
Once I converted my GeoJson into TopoJson I was ready to start creating a map from it in D3.
My First D3 Map
I started with a basic map tutorial from Mike Bostock, creator of D3: http://bost.ocks.org/mike/map/
Initially I wasn't able to get it working, but it was because I was using GeoJson. Switching to TopoJson helped me make sense of some of the Javascript - there's a lot that's happening implicitly even in the simplest D3 examples. Opening the TopoJson to understand its structure and keys, how properties were stored in it, made the D3 more clear.
Here is the final map created for the tutorial: http://bost.ocks.org/mike/map/step-7.html
The main point that gave me trouble was figuring out the projection. With Leaflet, I can pass latitude and longitude to center the map on my region of interest. But this wasn't possible (or, more likely, I couldn't figure out how to do it) with D3.
I ended up using a US projection, which led to this funny rotation of California, out there on the left coast:
When I tried rotating or transforming it, it would disappear for any setting more than very tiny numbers, and it is really inefficient to position a map like you draw with an etch-a-sketch. Need to figure out how to use latitude and longitude. And maybe how to add tiles?
Step 1: The Data
First, I was using a GeoJson file from the US Census. This encoded some data about method of commuting to work by poverty status. I wanted to test whether I could preserve properties encoded in the GeoJson when I converted it to TopoJson, since the whole point of using D3 is to take advantage of its data-crunching capabilities.
When I ran the topojson command to convert GeoJson to TopoJson, I used the -p flag.
Step 2: The D3 Javascript
I began with specifying information about the canvas, projection, and setup of D3:
var width = 800,
height = 600;
var projection = d3.geo.albersUsa()
.scale(1400)
.translate([width*3/4, height/2]);
var path = d3.geo.path()
.projection(projection)
.pointRadius(2);
// This is inserted as <body> is being constructed,
// so <svg> occurs wherever this .js file is called.
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
Next, we iterate over each TopoJson feature and extract properties. We use the geoid property to create a unique style for each California county. If we had multiple states, we could give each state's counties unique CSS classes. This would ease changing styles on a state-by-state basis. I've also encoded the geoid, which is unique to that county, so that we can map colors to data, or pick out one particular county (as with San Bernadino County in the D3 example on a-shrubbery).
var prefix = "/";
// this Json file is TopoJson:
d3.json(prefix+"d3basicmap.json", function(error, ca) {
//console.log(ca);
var subunits = topojson.feature(ca, ca.objects.d3basicmap);
console.log(subunits);
svg.selectAll(".subunit")
.data(subunits.features)
.enter().append("path")
.attr("class", function(d) { return "subunit subunit" + d.properties.geoid; })
.attr("d", path);
});
This can all be found on Github: https://github.com/charlesreid1/a-shrubbery/blob/master/pelican/maps/d3basicmap.js
Step 3: D3 HTML
I added all of this to an HTML document as follows.
The script above appends an <svg> tag to the <body> tag wherever I place the <script>.
I add the following to an HTML document, wherever I want my D3 content to go:
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script src="{{ SITEURL }}/d3basicmap.js" type="text/javascript"></script>
where Template:SITEURL is Jinja template markup, part of using Pelican to manage all the maps on the page.
Pelican/Jinja template on Github here: https://github.com/charlesreid1/a-shrubbery/blob/master/pelican/maps/d3basicmap.html
Workflow: D3 for Topo Maps
If this owrks, it'll be great:
http://stackoverflow.com/questions/18300527/d3js-how-to-design-topographic-maps