districts api
This freely-available API tells you which political districts contain a given point in Canada.
Quick Summary
http://api.vote.ca/api/beta/districts?lat=45.52&lng=-73.59
returns
[
{
"source_id": "24047",
"uptodate": [2010, 9, 24],
"name": "Outremont",
"electoral_group": {
"province": "",
"name": "Canada",
"level": "Federal"
}
},
{
"source_id": "62",
"uptodate": [2010, 9, 24],
"name": "Mercier",
"electoral_group": {
"province": "QC",
"name": "Québec",
"level": "Provincial"
}
}
]
Rate Limits
Calls are rate-limited by IP; at the moment, you get roughly 10 requests per minute. If you exceed your rate limit, the API will return HTTP status code 503. If your needs exceed this limit, please get in touch.
Future Changes
This is a new API, and it will change. (In particular, there is currently no concept of changing district boundaries. That'll need to be added relatively soon.) While we'll certainly aim to maintain backwards compatibility, there's not yet any promise of API stability. And, while current functionality will remain free, the API may at some point require authentication. That's why, if you use this API, you should sign up below for a (very low-traffic, announcement-only) mailing list:
Usage
The base URL for the API is http://api.vote.ca/api/beta/ . "beta" is the current API version number.
Calls return JSON by default. Adding format=xml to the query string will return XML instead, though it's a (kinda ugly) XML serialization of a data structure designed for JSON. JSONP is supported via a callback= parameter.
Currently a single call is available, districts. It takes two required GET parameters, lat and lng. These are the latitude and longitude (in the WGS84 spatial reference system, which is what pretty much any geocoder will return to you) of a point in Canada. Sample URL: http://api.vote.ca/api/beta/districts?lat=45.52&lng=-73.59
The return value is an array of district results. Each district result is a hash with the following keys:
| Key | Description |
|---|---|
| name | The name of the district, e.g. Toronto Centre. |
| source_id | An ID string used for the district in the original data file the district shape was loaded from. For federal ridings, this is the standard Electoral District ID. |
| uptodate | The date on which this district was loaded or verified as current. Represented as an array of [year, month, day]. |
| electoral_group | The set of political districts this district belongs to—e.g. Quebec Assemblée Nationale districts or Toronto city wards. Represented as a hash with three keys:
|
When no districts are found for a given point—this should only happen for points outside Canada—the response will be an empty array, but will still be delivered with HTTP status code 200.
Coverage
At the moment, the API is aware of the following groups of districts:
- Canada (Federal)
- Alberta (Provincial)
- British Columbia (Provincial)
- Manitoba (Provincial)
- Newfoundland & Labrador (Provincial)
- Nova Scotia (Provincial)
- Ontario (Provincial)
- Prince Edward Island (Provincial)
- Québec (Provincial)
- Saskatchewan (Provincial)
- Calgary, AB (Municipal)
- Edmonton, AB (Municipal)
- Ottawa, ON (Municipal)
- Toronto, ON (Municipal)
Contact & Data
Contact michael@michaelmulley.com with questions and comments.
New electoral-district data is highly welcome! If you have data, please send it along, and try to ensure it meets the following criteria:
- In a common geospatial data format: KML, GML, ESRI shapefile
- Uses the WGS84 spatial reference system, if possible. (All KML files use this.) If the file uses another spatial reference system, it'd be great if you could include its EPSG authority number.
- Includes a single feature for each political district (multipolygon features are fine, but each political district should have a single row in the attribute table). Attributes should provide a name and, optionally, ID number for each district.
- Should include no features other than the relevant political districts
Thanks!
Example
This example uses the Google Maps geocoder to match an address with its political districts.
Here's the code:
<form id="districtsapidemo"> <table> <tr><th>Your address</th><td><input type="text" style="width: 400px"></td></tr> <tr><td></td><td><input type="submit" value="Go"></td></tr> </table></form> <div id="districtsapidemo_message"></div> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script> <script type="text/javascript">var $message_area = $('#districtsapidemo_message'); $('#districtsapidemo').submit(function (e) { e.preventDefault(); // First, find the latitude and longitude for this address var geocoder = new google.maps.Geocoder(); geocoder.geocode({'address': $('#districtsapidemo input[type=text]').val(), 'region': 'ca'}, function(results, status) { $message_area.children().remove(); // A fuller example would only look at street addresses if (results.length > 1) { // Resolve multiple possible addresses $message_area.append('<p>Which of these looks like your address?</p>'); $.each(results, function() { var result = this; $message_area.append($('<p>' + this.formatted_address + '</p>').click(function () { districts_for_geocoder_result(result); })); }) } else if (results.length == 0) { $message_area.append('<p>No match for that address.</p>'); } else { districts_for_geocoder_result(results[0]) } }); }); // Call this function once we have a latitude and longitude function districts_for_geocoder_result(result) { // 'result' is a Google geocoder response object // latitude lives in result.geometry.location.lat() $message_area.children().remove(); $message_area.append('<p>' + result.formatted_address + '</p>'); $.getJSON('http://api.vote.ca/api/beta/districts?callback=?&' + $.param({ 'lat': result.geometry.location.lat(), 'lng': result.geometry.location.lng()}), function (data) { if (data.length == 0) { $message_area.append('<p>No districts found. Is that address in Canada?</p>'); } $.each(data, function () { $message_area.append('<p>In ' + this.electoral_group.name + ' (' + this.electoral_group.level + '), your district is ' + this.name + '.</p>'); }); } ); } </script>