Next year the 2010 Census data will be coming out, and shortly after that redistricting will be in full swing across the US.
Redistricting for our County Commisioner districts is a very simple affair. The districts are composed of voting precincts, so redistricting in this context means assigning a voting precinct polygon a new commissioner district number. No linework changes are involved, and a quick glance at our current districts will tell you SCOTUS’ idea of “compactness” of districts is not a consideration. We pre-calculate whatever stats we need by voting precinct, and the rest is basic arithmetic.
There are a number of redistricting software packages around, including lots of Esri extensions and a particularly cool open source project that’s in alpha. But they’re all a bit heavy for what we need, not to mention pricey for the Esri ones, so I figured I’d take a stab at it and see what I could come up with. After ~6 hours or so over two days, here’s what I’ve got.
Yes, I know it’s ugly. If we really use it I’ll pretty it up. And the data is all randomly generated garbage. But just as a test of the idea, by golly I think it’ll work.
It’s OpenLayers, jQuery, the Google Charts API, and our voting precincts as geojson. I simplified the bejeesus out of our voting precincts layer, since all I’ll care about in the end is the precinct number and the district assignment. That droped the geojson down to a web-friendly 140kb. Then it was a matter of loading it as a vector, setting a select control, and iterating through the vectors when something changes. It’s all client side code so you can look at the (somewhat rough) source, but I’ll just point out a few of the salient bits.
First, the vector layer setup. I’m using a StyleMap with a lookup to set the colors of the precincts. I’m loading the geojson as a file and then adding the vectors to the layer rather than loading it with the vector layer. No particular reason for that - it just seems cleaner to me.
// Load vectors from geojson url = "data/cc.json"; OpenLayers.loadURL(url, {}, null, function(r) { var p = new OpenLayers.Format.GeoJSON(); var f = p.read(r.responseText); vectors.addFeatures(f); updateValues(); });
For the vector layer’s select event, make sure you tell the feature explicitly to draw. Otherwise it won’t change colors to the new district until another select or unselect event fires.
You’ll be running through the whole features array in the updateValues function, so it pays to think this through. Never make a long loop with a jQuery lookup, like $(“#myelement”), as it will have to do a DOM search each and every time and performance will suffer. Here I’m using arrays to hold the summary stats until the end. The red/green bit is for potential constraints, like the district populations have to be within 10% of each other.
// Set some vars so we're not doing a dom search a hundreds of times
var popSummary = newArray(); var repSummary = newArray(); var demSummary = newArray(); var blackSummary = newArray(); var whiteSummary = newArray(); var hispanicSummary = newArray();
for (i = 1; i < 7; i++) { popSummary[i] = 0; repSummary[i] = 0; demSummary[i] = 0; blackSummary[i] = 0; whiteSummary[i] = 0; hispanicSummary[i] = 0; }
// loop through vectors feats = vectors.features; for(i = 0; i < feats.length; i++) { feature = feats[i];
// Set table values from arrays for (i = 1; i < 7; i++) { $("#pop-"+i).html(popSummary[i]); $("#rep-"+i).html(repSummary[i]); $("#dem-"+i).html(demSummary[i]); $("#black-"+i).html(blackSummary[i]); $("#white-"+i).html(whiteSummary[i]); $("#hispanic-"+i).html(hispanicSummary[i]); }
// add red/bold style if criteria not met $("#summary-stats .population").each( function(intIndex) { if (parseInt( $( this ).html() ) > 189061 || parseInt( $( this ).html() ) < 154687 ) $(this).addClass("badValue").removeClass("goodValue"); else $(this).addClass("goodValue").removeClass("badValue"); });