API Access: Twitter

The following is an introduction to the Twitter API about pulling data from Twitter for use in your maproom.

First, go to Twitter’s developer page. The general guidelines and various API support articles are available from this page. Unlike YELP and Flickr’s API there is no need to obtain an API key when making calls to Twitter’s search API.

Setting up

Start with an empty maproom layout:
Sample Code

Notice the new global variable created:

1
2
//array to hold twitter markers
var twitter = [];

Creating a function that calls Twitter’s API

In this tutorial, we will be using Twitter’s tweet search API documented here. We will be using the geocode and rpp arguments to create a search that returns up to 25 tweets around a center point. To make this API call, input the following URL:

http://search.twitter.com/search.json?rpp=25&geocode=34.0522342,-118.4911912,20mi&callback=?

Let’s break this down:

  • rpp: the number of tweets to return per page (max 100)
  • geocode: parameter returns tweets within a given radius based on a latitude/longitude

Now let’s create a new function that generates this URL based on the center latitude and longitude of the map. Google has a function to get the current center latitude and longitude coordinates which we will use:

  • map.getCenter().lat()
  • map.getCenter().lng()

Here’s the function:

1
2
3
4
5
6
7
8
9
10
11
//Function to get data from Twitter
ryan.getTwitter = function()
{
    bounds = new google.maps.LatLngBounds ();
    $.getJSON('http://search.twitter.com/search.json?rpp=25&geocode='+map.getCenter().lat()+','+map.getCenter().lng()+',20mi&callback=?',
        function(data)
        {
                trace(data);
        }
    );
}

Tracing the data to see what we need

Notice that we are using the trace function to see what gets returned first. Using Chrome’s developer tools, see what appears in the console window.

Twitter Trace

Twitter Trace

According to this, the following are the key parameters we need:

  • object -> results (array) -> from_user
  • object -> results (array) -> location
  • object -> results (array) -> geo
  • object -> results (array) -> profile_image_url
  • object -> results (array) -> text

Creating a function to map the Geotagged Tweets

As you will notice, the majority of tweets returned do not have longitude/latitude data specified. Instead a general location such as a city is given. For now, we will ignore those tweets and focus on those that are geotagged.

First, we need to modify our getTwitter function to account for geotagged and non-geotagged tweets:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//Function to get data from Twitter
ryan.getTwitter = function()
{
    removeLayer();
    bounds = new google.maps.LatLngBounds ();
    $.getJSON('http://search.twitter.com/search.json?rpp=25&geocode='+map.getCenter().lat()+','+map.getCenter().lng()+',20mi&callback=?',
        function(data)
        {
            $.each(data.results, function(i,item){
                if (item.geo == null)
                {
                trace(i + ' no geo data');
                }
                else
                {
                infoWindowContent = '<strong>'+item.from_user+'</strong><br>';
                infoWindowContent += '<img src="'+item.profile_image_url+'"></a><br>';
                infoWindowContent += ''+item.text+'';
ryan.createTwitterMarker(i,item.geo.coordinates[0],item.geo.coordinates[1],infoWindowContent,item.profile_image_url);
                }    
            });
        });
}

For now, if an item has no geodata we will trace the message “No Geo Data” in the console. However, if a tweet has geodata we will create an Infowindow with the from_user, profile_image_url, and text variables and pass this infowindow along with the lat/long (geo.coordinates[0], geo.coordinates[1]) to the function createTwitterMarker which we will create next.

Creating a second function to map the results

Now let’s create a second function that maps these results:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//Function to create Twitter Marker
ryan.createTwitterMarker = function(i,latitude,longitude,infoWindowContent,icon)
{
    var markerLatLng = new google.maps.LatLng(latitude,longitude);  
   
    //extent bounds for each Tweet and adjust map to fit to it
    bounds.extend(markerLatLng);
    map.fitBounds(bounds);
    var image = new google.maps.MarkerImage(icon, null, null, null, new google.maps.Size(32,32));

    twitter[i] = new google.maps.Marker({
        position: markerLatLng,
        map: map,
        title: infoWindowContent,
        icon: image
        });
       
    //add an onclick event
    google.maps.event.addListener(twitter[i], 'click', function() {
        infowindow.setContent(infoWindowContent);
        infowindow.open(map,twitter[i]);
        });
}

Creating a function to Geocode the results

Now let’s go back to those Tweets that had no geodata attached. In this step, we will write a function to automatically geocode the city received into its latitude/longitude coordinates.

First, we need to create another global variable

1
2
//declare geocoder
var geocoder;

Next, we need to modify our getTwitter function one final time:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//Function to get data from Twitter
ryan.getTwitter = function()
{
    removeLayer();
    bounds = new google.maps.LatLngBounds ();
    $.getJSON('http://search.twitter.com/search.json?rpp=25&amp;geocode='+map.getCenter().lat()+','+map.getCenter().lng()+',20mi&amp;callback=?',
        function(data)
        {
            $.each(data.results, function(i,item){
                if (item.geo == null)
                {
                infoWindowContent = '<strong>'+item.from_user+'</strong><br>';
                infoWindowContent += '<img src="'+item.profile_image_url+'"></a><br>';
                infoWindowContent += ''+item.text+'';
                ryan.geocodeTwitter(i,item.location,infoWindowContent,item.profile_image_url);
                }
                else
                {
                infoWindowContent = '<strong>'+item.from_user+'</strong><br>';
                infoWindowContent += '<img src="'+item.profile_image_url+'"></a><br>';
                infoWindowContent += ''+item.text+'';
ryan.createTwitterMarker(i,item.geo.coordinates[0],item.geo.coordinates[1],infoWindowContent,item.profile_image_url);
                }    
            });
        });
}

In this new iteration of the getTwitter we define what the function does when it encounters a non-geotagged tweet. The function will still generate an infowindow as before but instead of passing the lat/long to the createTwitterMarker function, it passes the location of the tweet along with the infowindow information to the geocodeTwitter function that we will be creating next.

Now, we will create the geocoder function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ryan.geocodeTwitter = function(i,genLocation,infoWindowContent,icon)
{
    var geocoderRequest = {address: genLocation}
    geocoder.geocode(geocoderRequest, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK)
        {
ryan.createTwitterMarker(i,results[0].geometry.location.Da,results[0].geometry.location.Ea,infoWindowContent,icon);
            trace(i + ' lat/long');
            trace(results[0].geometry.location);
        }
        else
        {
            trace("Geocode was not successful for the following reason: " + status);
        }
    });
}

In this function the location will be run through Google’s geocoder function. If the geocode is successful a lat/long will be returned which we can then use to feed into the createTwitterMarker function. If the geocode fails, an error message will be displayed in the console.

Note: There is a limitation on Google’s geocoder function. Since it takes a large amount of resources to geocode locations on demand, Google limits the use of this function to 2500 requests every 24 hours from a single IP address. Just keep in mind, that if you pass this limit, your geocodes will start to fail and you will receive an “over the limit” error in your console.

Finally, you need to add the geocoder variable to your initialize function:

1
geocoder = new google.maps.Geocoder();

Note: One additional quirk of using the Geocoder function for geocoding tweets. Since many tweets will be feeding the same location (ie. Los Angeles) into the Geocoder function you will get many Tweets mapped to the same exact lat/long. The result is many tweets stacked onto the same location with only the top tweet being visible/clickable. If you queried 25 tweets but only see a few, the majority of them are probably all stacked on the center of Los Angeles.

Complete code example

Sample Code

Leave a Reply