I'm using the D3.js library to create maps from US Census shapefiles. I'm looking to create an entire US map, which is no problem, and a map for each state.
My workflow uses the census data, altered as necessary by ogr2ogr at the command line, then converted into topojson or geojson by shpescape.com, due to errors in the node.js downloading of the topojson module (see below for edited solution to this particular problem).
My question is more of a PRACTICAL question than anything else--when presented with this code (modeled off of http://bl.ocks.org/mbostock/4707858):
var width = 640,
height = 500;
var projection = d3.geo.albers();
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("mt_geo.json", function(error, mt_topo) {
var states = topojson.feature(mt_topo, mt_topo.objects.states),
state = states.features.filter(function(d) { return d.id === 34; })[0];
projection
.scale(1)
.translate([0,0]);
var b = path.bounds(state),
s = .95 / Math.max ((b[1][0]-b[0][0])/width, (b[1][1]-b[0][1])/height),
t = [(width-s*(b[1][0]+b[0][0]))/2, (height-s*(b[1][1]+b[0][1]))/2];
projection
.scale(s)
.translate(t);
svg.append("path")
.datum(states)
.attr("class", "feature")
.attr("d", path);
svg.append("path")
.datum(topojson.mesh(us, us.objects.states,function(a, b) {return a !== b;}))
.attr("d", path);
svg.append("path")
.datum(state)
.attr("class", "outline")
.attr("d", path);
Not only does it throw an error at the "var states" line which says "cannot read type of property undefined" -- but I also have no idea what I'm supposed to be passing into the anonymous function, or what mt_topo.objects.states is supposed to refer to. There is no good documentation on this sort of GIS thing. Do all census maps have "state" features? Do you lose that information when you compress the .shp to topojson?
Simply, if d3.json takes (object, function(error, json)), what would an example of that which works actually look like?
EDIT: WORKAROUND AND WINDOWS 7 IDIOSYNCRASIES -----
Most tutorials tell you to use a module from node.js, but I'm on Windows7, and the canonical command-line "npm install -g topojson" fails "at contextify". The creator sent me a nice link to work around said problem.
This is important, because there is a flag in the command line for topojson in which you can package existing features in geojson into an accessible object in topojson. For example, the above code uses "states" in topojson--something that is meaningless and unaccessible unless you use the following command:
topojson -o us.topojson -- states=us_states.json
The space between the double hyphen and states is important. You can then access the states via us.objects.states, as shown in the original code above.
You're very close. Without testing your code, I see one major issue. The second parameter of your JSON callback is mt_topo
, which you use when defining
var states = topojson.feature(mt_topo, mt_topo.objects.states)
However, later on you use us
as your callback object, presumably because that is what Mike Bostock used in the example you cited. Instead, it should be this:
svg.append("path")
.datum(topojson.mesh(mt_topo, mt_topo.objects.states,function(a, b) {return a !== b;}))
.attr("d", path);
That said, your question is really getting at whether or not census maps have a "states" feature. My guess is that whatever geometry you are using does not have a states feature, and that is why you are getting an error. When using the topojson command line tool, the feature name (i.e. data.objects.x) is usually whatever the input file was named, so if your file was US_Census_2010.shp
, you would want to define states as
var states = topojson.feature(mt_topo, mt_topo.objects.US_Census_2010)
Open up your mt_geo.json
file and see what your features are named. Hope that helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With