This web app is composed entirely of flat files. Here is its published incarnation.
- Incorporates new results relatively quickly, sending them to the live site.
- Shows the electoral districts on a map:
- Montreal district shapefiles come from the city.
- Outside the City of Montreal, we operate on the assumption that Municipal Affairs groups results by Census Subdivision. We use Statistics Canada shapefiles.
- Allows searching for results by postal code. This is hard:
- We precompute cities' postal code to district IDs, using a list of all voting households.
- We precompute some Forward Sortation Areas to Census Subdivision IDs, when the FSA is entirely contained within the Census Subdivision.
- For the rest, we geocode using Google Maps and then find the electoral region ID by searching for the matching polygon with a Fusion Tables query. (This would work in all cases, but we use the above two strategies to avoid hitting our quota.)
- A Google Fusion Table holds all electoral regions and their IDs. Users see this map on page load. They also query it when searching for some postal codes outside of Montreal.
- When the user searches for some postal codes outside of Montreal, we send a request to the Google Maps Geocoder (with just the postal code).
- When the user chooses a Montreal district (by clicking or searching by postal code), we request a topojson file to display on top of the Fusion Table.
- When the user chooses a non-Montreal district (by clicking or searching by postal code), we request a topojson file to display on top of the Fusion Table, and we request the election results.
The design is the way it is because it provided all features on deadline. It's not the best.
To make it better:
- Montreal election results shouldn't be baked into the JSON. (The municipalities' aren't.) Results should be separate.
This section assumes you're comfortable with the command-line and typical web development tools.
- Prerequisites: NodeJS, Python 3.x, Bash (the default shell on Mac OS X and most Linux varieties)
- Node Package Manager dependencies:
npm install -g bower grunt-cli coffee-script - Download the files described in
data/raw/README.md - If you want to re-generate polygons (you don't have to):
- Install GDAL's ogr2ogr.
data/gen-shapefile.shto builddata/processed/polygons/*.jsonanddata/processed/tmp/districts.shp.cp data/processed/polygons webapp/app/polygonsto copy the polygons into the web app.- Upload
data/processed/tmp/districts.shpto a new Google Fusion Tables table. - Publish the Fusion Table, and edit the id in
webapp/app/scripts/main.coffeeto be the one you just published.
data/gen-postal-code-to-district.pyto createdata/processed/district-to-postal-codes.json, which helps convert from postal code to district. (Why the backwards name? Inverting the lookup table takes fewer bytes; the client will re-generate the original from the inverted one.)data/gen-montreal-vote-data.pyto createdata/processed/montreal-data.json, the Montreal election resultsdata/finalize.py && cp data/processed/data.js webapp/app/scripts/data.jsto put the postal-code data and Montreal election results in a JavaScript file.- Edit
webapp/app/scripts/main.coffeeand set a Google API Key you generate yourself. To generate an API Key: go to https://cloud.google.com/console, choose "APIs & auth", "Registered apps" and "Register app". - Edit
webapp/app/index.htmland change the Google Analytics ID. - Start the webapp locally to test it works:
cd webapp(we'll be here for the rest of this step)npm install && bower installto download dependencies (locally)grunt serverto run a server locally (it will open in your browser). Press Ctrl-C when satisfied, or leave it running throughout.
- Add the non-Montreal election results:
mkdir -p webapp/app/cached-donnees.electionsmunicipales.gouv.qc.ca && cd webapp/app/cached-donnees.electionsmunicipales.gouv.qc.ca(we'll be here for the rest of this step)- Download all the files:
for uid in $(cat ../../../data/raw/json-list.txt); do echo "$uid..."; curl "http://donnees.electionsmunicipales.gouv.qc.ca/$uid.json?CACHE_BUST=${RANDOM}${RANDOM}" -o "$uid.json" "-#"; sleep 1; done(or use curl instead of wget)
- Deploy the server:
cd webapp && grunt build- Copy the contents of
webapp/distonto any static file server. Point users at theindex.htmlfile within.
Public Domain. See LICENSE.