Skip to content

Instantly share code, notes, and snippets.

@dougmarcey
Created November 1, 2013 21:05
Show Gist options
  • Save dougmarcey/7271937 to your computer and use it in GitHub Desktop.
Save dougmarcey/7271937 to your computer and use it in GitHub Desktop.
#!/usr/bin/env node
var path = require("path"),
fs = require("fs"),
dsv = require("dsv"),
optimist = require("optimist"),
queue = require("queue-async"),
topojson = require("topojson"),
jsts = require("jsts"),
d3 = require("d3");
var us = JSON.parse(fs.readFileSync("../us-counties.json", "utf-8"));
var top = {}, transform = us.transform;
var counties = d3.map();
var msas = d3.map();
var eas = d3.map();
for (var key in us.objects) {
console.log(key);
top[key] = topojson.feature(us, us.objects[key]);
}
console.log("top level objects: " + top);
console.log("counties: " + top.counties.type);
us.objects.counties.geometries.forEach(function(c) {
counties.set(c.id, topojson.feature(us, c));
});
var reader = new jsts.io.GeoJSONReader();
var writer = new jsts.io.GeoJSONWriter();
top['msa'] = {type: "FeatureCollection", features: []};
top['ea'] = {type: "FeatureCollection", features: []};
fs.readFile("../msa.csv", "utf-8", function(error, text){
var count = 0;
dsv.csv.parse(text).map(function(row) {
var msa_id = +row.regiongroup_id;
var fips = row.region_code;
if (!msas.has(msa_id)) {
msas.set(msa_id, { id: msa_id, name: row.name_msa, counties: d3.set()});
}
msa = msas.get(msa_id);
msa.counties.add(fips);
count++;
});
var largest = 0;
var i = 1;
var errors = [];
var invalid = 0;
msas.forEach(function(_id ,msa) {
console.log(i + "/" + msas.keys().length + " " + msa.name);
msa.counties = msa.counties.values();
if (msa.counties.length > largest) {
largest = msa.counties.length;
}
var msa_geo;
var geos = [];
msa.counties.forEach(function(cid) {
var c = counties.get(cid);
if (!c) {
console.log(" Could not file county: " + cid + " for msa: " + msa.id + " -- " + msa.name);
} else {
var geo = reader.read(c.geometry);
geo.buffer(0);
var isValidOp = new jsts.operation.valid.IsValidOp(geo);
if (!isValidOp.isValid()) invalid++;
geos.push(geo);
try {
msa_geo = ( msa_geo ? msa_geo.union(geo) : geo);
} catch (ex) {
errors.push({msa: msa.name, id: msa.id, valid: (isValidOp.isValid() ? true: isValidOp.getValidationError()), error: ex, county: cid});
}
}
});
if (!msa_geo) console.log("not geo for msa: " + msa.name);
else {
msa.feature = {type: "Feature", id: msa.id, geometry: writer.write(msa_geo)};
top['msa'].features.push(msa.feature);
}
i++;
});
console.log("invalid: " + invalid);
console.log("errors: " + errors.length);
console.log("mappings: " + count);
console.log("msa count: " + msas.keys().length);
console.log("largest msa: " + largest + " counties");
fs.readFile("../ea.csv", "utf-8", function(error, text) {
var count = 0;
dsv.csv.parse(text).map(function(row) {
//ea_code,eax,fips,county_name
var ea_id = +row.ea_code;
var fips = row.fips;
if (!eas.has(ea_id)) {
eas.set(ea_id, { id: ea_id, eax: row.eax, counties: d3.set()});
}
ea = eas.get(ea_id);
ea.counties.add(fips);
count++;
});
var i = 0;
eas.forEach(function(_id, ea) {
console.log(++i + "/" + eas.keys().length + " " + ea.id);
ea.counties = ea.counties.values();
var ea_geo;
var geos = [];
var j = 0;
ea.counties.forEach(function(cid) {
console.log("\t" + ++j + "/" + ea.counties.length + " counties");
var c = counties.get(cid);
if (!c) {
console.log(" Could not find county: " + cid + " for ea: " + ea.id + " -- " + ea.eax);
} else {
var geo = reader.read(c.geometry);
geo.buffer(0);
var isValidOp = new jsts.operation.valid.IsValidOp(geo);
geos.push(geo);
try {
ea_geo = ( ea_geo ? ea_geo.union(geo) : geo);
} catch (ex) {
errors.push({ea: ea.eax, id: ea.id, valid: (isValidOp.isValid() ? true: isValidOp.getValidationError()), error: ex, county: cid});
}
}
});
if (!ea_geo) console.log("not geo for ea: " + ea.id);
else {
ea.feature = {type: "Feature", id: ea.id, geometry: writer.write(ea_geo)};
top['ea'].features.push(ea.feature);
}
});
output(top, 1, "output.json");
});
});
function print_errors(errors) {
if (errors.length > 0) {
console.log("Errors");
console.log("===========");
errors.forEach(function(e) {
console.log(" ID: " + e.id);
console.log(" Name: " + e.msa);
console.log("County: " + e.county);
console.log(" Valid: " + e.valid);
console.log(" Error: " + e.error);
console.log(" GEO: " + JSON.stringify(e.geom));
console.log(" MGEO: " + JSON.stringify(e.msag));
console.log();
});
}
}
function output(objects, min_area, file) {
var options = {
"verbose": true,
"quantization": 1e4,
"coordinate-system": "cartesian",
"id": function(d) { return d.id }
};
// Convert GeoJSON to TopoJSON.
var object = topojson.topology(objects, options);
// Simplify.
topojson.simplify(object, {
"verbose": true,
"coordinate-system": options["coordinate-system"],
"minimum-area": min_area
// "retain-proportion": +argv["simplify-proportion"]
});
topojson.clockwise(object, {
"verbose": true,
"coordinate-system": options["coordinate-system"]
});
topojson.filter(object, {
"verbose": true,
"coordinate-system": options["coordinate-system"]
});
// Bind with external properties.
// if (argv.e) topojson.bind(object, externalProperties);
delete object.bbox;
// Output JSON.
var json = JSON.stringify(object);
fs.writeFileSync(file, json, "utf8");
}
// Build same for EA
// Create data file that maps country names, containing ea, msa, state
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment