Find your Green Candidate

In my spare evening hours here in New Hampshire this week I worked on a “Find your Green Candidate” widget for the Green Party campaign website.

This turned out not to be a trivial thing do to, in part because I couldn’t find a ready-made open data source of which civic addresses are in which electoral district. So I had take the electoral districts GIS layer and the civic address layer and use QGIS to run a point-in-polygon process to marry the two. The result was a MySQL table that looks like this:

Screen shot (detail) of electoral districts table

The table maps each civic address to its electoral district: like 71 48 RD is in District 2, for example.

Next I had to create a table of Green Party candidates, also keyed to electoral district:

Screen shot (detail) of candidates table

With this table I can look up who the Green candidate is for District 2, Susan Hartley.

With the data in place, I wrote an API, in PHP, that accepts a civic address fragment and returns matching addresses as an HTML fragment. For example, if I POST 99 B to this API, I get back:

<ul id="addresslist">
    <li class="oneaddress" id="23|Tyne Valley - Sherbrooke|Trish Altass|https://www.greenparty.pe.ca/trishaltass_d23|https://d3n8a8pro7vhmx.cloudfront.net/greenpartype/pages/2026/attachments/original/1554002031/smaller_trish_altass.png?1554002031|99 BAGLOLE WHARF RD">99 BAGLOLE WHARF RD, SOUTHWEST LOT 16</li>
    <li class="oneaddress" id="21|Summerside - Wilmot|Lynne Lund|https://www.greenparty.pe.ca/lynnelund_d21|https://d3n8a8pro7vhmx.cloudfront.net/greenpartype/pages/2026/attachments/original/1554002024/smaller_lynne_lund.png?1554002024|99 BALCOM DR">99 BALCOM DR, SUMMERSIDE</li>
    <li class="oneaddress" id="8|Stanhope - Marshfield|Sarah Donald|https://www.greenparty.pe.ca/sarahdonald_d8|https://d3n8a8pro7vhmx.cloudfront.net/greenpartype/pages/2026/attachments/original/1554350635/smaller_sarah_donald.png?1554350635|99 BALD EAGLE LN">99 BALD EAGLE LN, MILLCOVE</li>
    <li class="oneaddress" id="11|Charlottetown - Belvedere|Hannah Bell|https://www.greenparty.pe.ca/hannahbell_d11|https://d3n8a8pro7vhmx.cloudfront.net/greenpartype/pages/2026/attachments/original/1554002022/smaller_hannah_bell.png?1554002022|99 BARBOUR CIR">99 BARBOUR CIR, CHARLOTTETOWN</li>
</ul>

In other words, the first four addresses that match that address. If I send a longer address fragment to the API, like 99 BAL, I get the subset of addresses that continue to match:

<ul id="addresslist">
    <li class="oneaddress" id="21|Summerside - Wilmot|Lynne Lund|https://www.greenparty.pe.ca/lynnelund_d21|https://d3n8a8pro7vhmx.cloudfront.net/greenpartype/pages/2026/attachments/original/1554002024/smaller_lynne_lund.png?1554002024|99 BALCOM DR">99 BALCOM DR, SUMMERSIDE</li>
    <li class="oneaddress" id="8|Stanhope - Marshfield|Sarah Donald|https://www.greenparty.pe.ca/sarahdonald_d8|https://d3n8a8pro7vhmx.cloudfront.net/greenpartype/pages/2026/attachments/original/1554350635/smaller_sarah_donald.png?1554350635|99 BALD EAGLE LN">99 BALD EAGLE LN, MILLCOVE</li>
</ul>

You’ll notice that the ID of the list items returns contains all the data I need to render the candidate information for any address; while this isn’t efficient in terms of the size of the API payload, it does mean that I don’t need to make a second API call to get candidate details.

With the API in place, I wrote a JavaScript app to manage the actual candidate lookup.

The nice thing about this approach is that it’s a standalone tool that can be used in the field to help electors find their Green Candidate (it’s installable as a progressive web app) and it’s also embeddable in any other website:

That’s how you see on the Green Party candidates page, and how you can put it on your own website by pasting in:

<iframe scrolling="no" src="https://c.ruk.ca/election/index.html" style="width: 100%; height: 250px; border:0; margin-bottom: 20px; overflow: hidden"></iframe>

Since first releasing this a few days ago, I’ve been tweaking the design so that it integrates well with the Green website, and so that it behaves well inside an iframe on both desktop and mobile. It’s been a fun exercise.

I welcome any feedback you might have on how it works (or, if it doesn’t, how it’s broken!).