## So, what’s this all about?

Essentially, Which Three Birdies?™©® is a chance to play with some nice APIs and stitch the results together. Xeno-Canto have recordings of birdsong from all around the world. Wikidata has pictures of all sorts of places and things. And 51Degrees can geolocate a point into a detailed native-language description of where that point is. Glue all those together and you’ve got... well, you’ve got a system for making a “birdday” card, right?

(The illusion of the single authorial "I" breaks for a moment here, where Stuart blames Bruce for the name and bangs his head frustratedly on the fourth wall. OK, no more asides to the audience. Back to the code.)

## (geo l-)O Captain, my captain! — geolocating a point ↑

Step 1 is to find a picture of a place. Well, we haven’t got a place; what we’ve got is some coordinates for a spot on the earth, latitude and longitude. So step zero is to find which place that is. Looking up a geographical point and giving it a name is the task of geolocation, and it is not as easy as you might think. Sometimes it’s simple enough: Big Ben is definitely in London, the Forbidden City is definitely in Beijing, and (as John Donne memorably wrote) Stormont is in Ireland. But which town is this field you’ve chosen closest to? What about the spot at the summit of Mount Kilimanjaro? If it’s not near a town, which region is it in? Which language should the answer be in? So we have someone else do the heavy lifting on that particular point.

Let’s try things for this place here: in the middle of the Green Mountain National Forest in the US state of Vermont. The birthplace (roughly) of Rachel Brooks Gleason, born this day in 1820, fourth woman to earn a medical degree in the United States, and anti-slavery activist: latitude 43.156702, longitude -72.914178.

First, a little code. This is PHP, but obviously it could be in JS or Python or C# or Java instead.

\$settings = array("resourceKey" => \$resourceKey,
"locationProvider" => "fiftyonedegrees");
\$builder = new GeoLocationPipelineBuilder(\$settings);
\$pipeline = \$builder->build();
\$flowData = \$pipeline->createFlowData();
\$flowData->evidence->set("query.51D_Pos_latitude", \$lat);
\$flowData->evidence->set("query.51D_Pos_longitude", \$lon);

\$result = \$flowData->process();

That will populate our \$flowData object with some or all of a town, a region, a state, and a country corresponding to the latitude (\$lat) and longitude (\$lon) we have. (You need an API key, what 51Degrees calls a “resource key”. See the 51Degrees API docs for details on the above functions.)

Now, not all of those things — town, region, state, country — are actually available for any given point. Some countries don’t really have “regions” or “states”; some points just aren’t very near an actual town at all. So we need to check whether each of those things are populated. The API does this in two ways; location->whatever might not be present at all, and if it is present it may have no value. So we check for each, and then we’ll have \$town, \$region, \$state, and \$country all either a string or null.

\$town = null; \$region = null; \$state = null; \$country = null;
try { \$town = \$flowData->location->town; } catch(Exception \$e) {}
try { \$region = \$flowData->location->region; } catch(Exception \$e) {}
try { \$state = \$flowData->location->state; } catch(Exception \$e) {}
try { \$country = \$flowData->location->country; } catch(Exception \$e) {}

if (!\$town->hasValue) \$town = null;
if (!\$region->hasValue) \$region = null;
if (!\$state->hasValue) \$state = null;
if (!\$country->hasValue) \$country = null;

In step 2 (spoilers!) we’ll be trying to look up this place name to get a picture for it. Even if we have all of town, region, state, and country, it’s possible that there is no picture available for that town; there are a lot of towns, after all. So we construct a series of locations, in decreasing order of specificity. If the place we have is “Anytown, Some Region, Thestate, Freedonia”, then we want to make a set of locations to look up as follows:

1. Anytown, Some Region, Thestate, Freedonia (town, region, state, country)
2. Anytown, Some Region, Freedonia (town, region, country)
3. Anytown, Thestate, Freedonia (town, state, country)
4. Some Region, Thestate, Freedonia (region, state, country)
5. Anytown, Freedonia (town, country)
6. Some Region, Freedonia (region, country)
7. Thestate, Freedonia (state, country)
8. Freedonia (country)

(We do it in this order specifically because we’re looking for pictures of this place. A picture of the town you’re in is best, but a picture of the region is still relevant, and a picture of the country as a whole isn’t too bad. This is why "town + country" is lower down the list than you might expect; there are an awful lot of countries which have two towns with the same name, and picking the wrong one isn’t ideal here.)

Our chosen location returns the following:

Town
Winhall
Region
null
State
Vermont
Country
United States of America

and our list of geolocations to search for is therefore

1. Winhall, Vermont, United States of America
2. Winhall, United States of America
3. Vermont, United States of America
4. United States of America

And with those in place, it’s on to step 2.

## A thousand words — picturing an address ↑

Wikidata is to structured data what Wikipedia is to human-readable knowledge: it’s got everything. In particular, you can search for pretty much anything you can think of and then find all the knowledge that Wikidata has about that thing, carefully characterised by type. For our purposes, you can search for a place, and then look for a record of type “P18” attached to it, which in Wikidata-speak means “a picture of this thing” (well, “image of relevant illustration of the subject”). This means that we can search for our address from step 1, look at the result we get back, and if it contains a P18 record then we have a picture of that address. This is why we needed to look up the latitude and longitude to get a human-readable address — it gives us something to search for.

First, search Wikidata for the address in question by constructing a search URL that returns JSON, which looks like:

That does indeed return us a result! The relevant part is this:

{
"title":"Q8025343",
"pageid":7971580,
"timestamp":"2020-01-11T18:30:56Z"
}

and the key part there is the title, "Q8025343", which is an “entity-id”, Wikidata-speak for a unique ID for a thing. This, usefully, lets us directly construct a URL to get all the data about that thing:

https://www.wikidata.org/wiki/ Special:EntityData/Q8025343.json

and that has all the info we need. In particular, there’s a claims.P18 record:

"P18": [
{
"mainsnak": {
"snaktype": "value",
"property": "P18",
"datavalue": {
"value": "Winhall River, West River Trail.jpg",
"type":"string"
},
"datatype": "commonsMedia"
},
"type": "statement",
"rank":"normal"
}
]

and the value there can be used to construct a URL for an image on Wikimedia with a specific width:

http://commons.wikimedia.org/wiki/ Special:FilePath/ Winhall%20River%2C%20West%20River%20Trail.jpg ?width=1000

## Four and twenty blackbirds baked in an API — finding birds for a location ↑

Xeno-Canto bills itself as “Sharing bird sounds from around the world”, and it’s a really comprehensive crowd-sourced database of birdsong and bird calls from everywhere on Earth, searchable by latitude and longitude. So we can use it to find details of birds and their calls from our chosen point! They have an excellent API which lets us do this programmatically, so let’s dive in.

https://www.xeno-canto.org/ api/2/recordings?query= lat:43.156702 lon:-72.914178

This returns comprehensive JSON listing recordings from the area: the first of which is of the Canada Goose, branta canadensis. The Latin will be relevant in a moment. This first record has relevant parts that look like this:

{
"id":"72752",
"gen":"Branta",
"rec":"Ezekiel S. Jakub",
"loc":"Turners Falls Canal, Massachusetts",
"lat":"42.593",
"lng":"-72.579",
"type":"Call",
"url":"\/\/www.xeno-canto.org\/72752",