At iSL, we’re excited about the Olympics – go world! – and we’re dreaming up new ways of engaging our global audience. As part of the process, we thought it’d be cool to find Instagram users with the most pull in this year’s Olympic host city, London, so we built a little web app.
Here’s How It All Goes Down
First we need to decide on a search target, e.g. a city. Next we look for photos taken in our target area, and finally we process the media to discover those people deemed interesting by society. Google Maps provides incredible groundwork for our first requirement. We use Instagram as our photo source and follower rank. Then we match usernames with Klout. Putting it all together we should end up with a live monitoring system configurable via Google Maps.
It would be awesome if Instagram had the streaming support that Twitter does thus simplifying the build of a truly live system. Instagram does offer a realtime solution via its subscription service, but it involves significant back and forth so managing rate limits becomes an extra problem to solve. For now we settle on basic media scans.
As you may already know, our super-computer-mobile-gizmo-phones are sending our geographic positions embedded in every photo we upload to Instagram. That geo info is then made available via an API. Both subscriptions and the standard REST endpoints allow us to filter results based on this geographic data.
Here’s where things get tricky. Geographic queries to Instagram are limited to a 5000m radius, and we may very well want to search a larger area than this. London, for example, is 1,577 km². To get around the limitation, we’ll perform multiple searches with the maximum allowable radius, repositioning each time until we cover our target area.
Using Math to Solve our Problems
The problem we’re faced with amounts to filling a big circle with little ones. It’s obvious we can’t fill the larger circle with fixed-sized smaller ones without overlapping. See?
Let’s think about squares for a minute and come back to circles. We can imagine a square that encloses the large circle. It’s easy to then break that square into smaller ones that, combined, cover the entirety of the larger square and by association, the enclosed circle.
Now if we stop to think that inside every circle lives a square, we have a solution to our overlapping problem.
Accounting for a 3D World
Life is good in 2-D. Don’t believe me? Read Flatland, and do your best to ignore its unfortunate classification of women – it does have other redeeming qualities.
Things get tricky when dealing with life on Earth. As you probably noticed, stuff around here exists in three dimensions. Translation: we need to map our convenient 2-D system to the real world.
If you’ve ever traveled by plane, you’ve benefited from the math that helps us all move from a to b when |a – b| is pretty big. Straight lines don’t happen; instead our flight path is curved with the Earth’s surface. Thankfully, lives aren’t at stake here so I opted to use a relatively simple method for computing coordinates.
I’m going to combine this with some of the math used to generate earlier figures to get our circle center generating function, in Python:
[cc escaped="true" lang="python"] def generate_circle_centers(lat, lng, radius): # One side of a unit of the grid measures the distance of the # side of the largest square that will fit in an Instagram # search circle. unit = (2 * INSTGRM_MAX_RAD) / math.sqrt(2) # Find bounds of the grid. Bounds exceed desired radius by less # than one unit. x_max = y_max = int(math.ceil(radius / unit)) # Generate centers for the grid without considering latitude # or longitude yet. ideal_centers = [[(unit*(i+.5),unit*(j+.5)) for i in range(-x_max,x_max+1) if i+.5<x_max and j+.5<y_max] for j in range(-y_max,y_max+1)] # Map the centers to lat lng values, in degrees. lng_change = lambda x, lat1, lat2: math.degrees( x/(EARTH_RADIUS*math.cos(math.radians( (lat1 + lat2)/2 )))) lat_change = lambda y: math.degrees(y/EARTH_RADIUS) centers =  for row in ideal_centers: for ic in row: y, x = ic # Skip circles that fall entirely outside of target. if math.sqrt(x**2 + y**2) > radius + INSTGRM_MAX_RAD: continue centers.append((lat_change(y)+lat,lng_change(x, lat, lat+lat_change(y))+lng)) return centers [/cc]
The Final Product
We’re scanning London for popular Instagram users. The yellow fill represents scans that successfully found people. We can also move and resize our target to look all over. Here we are back home.
So it looks like the smaller circular regions are being scanned. It should appropriately skip areas where people aren’t. Chicago sits at the southern tip of Lake Michigan, and I’m guessing there isn’t anyone uploading photos to Instagram from their boat. Let’s see what happens.
Reaching Out on Twitter
Now that Instagram users we may find interesting are scrolling past, let’s see about getting in touch. We found a high correlation between matching Twitter usernames and Instagram usernames for popular Instagram users so we query Twitter to see if the prospective account exists. If we get a match, a link to the user’s Twitter feed is included. Now @ those you like!