Ballot Guide
Last year I wrote Ballot Guide to learn Flutter and Firebase and to make election information more accessible.
The 2019 election is coming up in November, so I thought, hey I'll use my app to get more information. But there was nothing.
Google Civic Information API
I went to check the list of elections on the Google Civic Information API and indeed, they don't have our local elections here in Colorado. But I still want to see what will be on my ballot before actual election time. Fortunately, my county publishes a sample ballot on the election website:
My first thought was, woah there are lots of stuff to vote on! Looking closer though, multiple cities and school districts are listed, and I don't reside in all of them, so my actual ballot should have fewer items than this. Can I filter it down to only the items relevant to me?
My voting districts
I went back to the Google Civic Information API and used the voterInfoQuery end point to find my voting districts. That works for city council, but not school districts, because that API does not return them.
Looking around, I found the shapefiles for Special Districts on the Colorado Department of Local Affairs (DOLA) GIS page. Great! But how do I query shapefiles?
Turf.js
I found a javascript library: Turf.js. A few steps to transform the data:
- Convert shapefiles into GeoJSON though with QGIS.
- Use the Google Places Autocomplete API to convert my voting address into latitude and longitude.
- Call booleanPointInPolygon from Turf.js on all the districts to see which one matches my residence.
But that didn't work! I tried many things until I realized that the exported GeoJSON has points in (lng, lat) instead of (lat, lng). Gah! Need to write a script to convert that.
Split the sample ballot
Finally I have a way to find my school district. Now I need to split the sample ballot into each contest, and only show those matching mine. I create a Google spreadsheet and, gasp, copy and paste the data from the PDF by hand.
The worst are the ballot measures. The PDF is multi-column, and when I copy and paste the line runs from one column to the other, instead of go onto the logical next line. It was very not fun.
Ingest into Firebase
Once I have the information on Google sheet, I wrote a script to curl the tsv, convert to json, and upload it into Firebase using the Firebase Admin SDK.
Missing data
I have missing data on both the ballot side and the district side. For the ballot, not all counties have sample ballots yet, so I have to wait until closer to the election. On the district side, some cities are subdivided into wards. Google Civic Information does not always return ward information. And I don't always have the shapefiles to do it myself.
Annotations
With that, I am able to filter and display a sample ballot before the election. Mostly. However, I still want more information. Specifically, city council and school board contests are non-partisan, but I would like to know the registered party of the candidates.
Colorado voter registration information in public. Anyone can purchase the whole database for $50. The webiste voterrecords.com bought it and made a search interface out of it, so I queried the candidates and added that information to my Google sheet to be ingested into Firebase.
Try it out
You can see it in action at huddle4hope-districts.web.app, or embedded below:
Currently it works for Adams County, Boulder County, Larimer County and Weld County in Colorado. If you don't live in those counties, you can try these addresses:
- 9440 Hoffman Way, Thornton, CO
- 2000 Walnut St, Boulder, CO
- 2446 Reception Ct, Fort Collins, CO
- 1001 50th Ave, Greeley, CO
Let me know what you think!