Reverse Geocoding Part 2 — Using Google Maps APIs

In the previous article , I talked about how to find prefecture names from longitude and latitude data using GeoJSON with R and Exploratory. But as I mentioned, there are a couple of limitations with that approach. For example, it didn’t get the right address information when the locations happened to be outside of the areas that are defined in the GeoJSON file.

Also, it failed to get the address information for those that are outside of the area covered by GeoJSON. For example, there are a few places in the data that are actually in Korea, not in Japan, and obviously there are not such information in Japanese GeoJSON file.

Google Maps APIs

To address such problems, I’m going to use the reverse geocoding API in Google Maps APIs. Google Maps APIs are a set of REST APIs. For example, if you want to get the location information by longitude and latitude data (139.68 and 35.6512, for example), you can create a request URL like this.

https://maps.googleapis.com/maps/api/geocode/json?latlng=35.6512,139.68

This would return the following data in a JSON format.

{
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "マンションニュー池尻",
               "short_name" : "マンションニュー池尻",
               "types" : [ "premise" ]
            },
            {
               "long_name" : "31",
               "short_name" : "31",
               "types" : [ "premise" ]
            },
            {
               "long_name" : "11",
               "short_name" : "11",
               "types" : [ "political", "sublocality", "sublocality_level_4" ]
            },
            {
               "long_name" : "3 Chome",
               "short_name" : "3 Chome",
               "types" : [ "political", "sublocality", "sublocality_level_3" ]
            },
            {
               "long_name" : "Ikejiri",
               "short_name" : "Ikejiri",
               "types" : [ "political", "sublocality", "sublocality_level_2" ]
            },
            {
               "long_name" : "Setagaya-ku",
               "short_name" : "Setagaya-ku",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "Tōkyō-to",
               "short_name" : "Tōkyō-to",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "Japan",
               "short_name" : "JP",
               "types" : [ "country", "political" ]
            },
            {
               "long_name" : "154-0001",
               "short_name" : "154-0001",
               "types" : [ "postal_code" ]
            }
         ],
         "formatted_address" : "Japan, 〒154-0001 Tōkyō-to, Setagaya-ku, Ikejiri, 3 Chome−11−31 マンションニュー池尻",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 35.6519032,
                  "lng" : 139.6800108
               },
               "southwest" : {
                  "lat" : 35.6511394,
                  "lng" : 139.6791787
               }
            },
            "location" : {
               "lat" : 35.6514726,
               "lng" : 139.6795723
            },
            "location_type" : "ROOFTOP",
            "viewport" : {
               "northeast" : {
                  "lat" : 35.65287028029149,
                  "lng" : 139.6809437302915
               },
               "southwest" : {
                  "lat" : 35.6501723197085,
                  "lng" : 139.6782457697085
               }
            }
         },
         "place_id" : "ChIJybykdFjzGGARYHWpyLrlwOU",
         "types" : [ "premise" ]
      },
      {
         "address_components" : [
                           :
                           :
                           :
                           :

It returns multiple addresses that match with the geocode. Each address contains an “address_components” object, and you can find the prefecture name in a component with “administrative_area_level_1” type.

                           :
                           :
            {
               "long_name" : "Tōkyō-to",
               "short_name" : "Tōkyō-to",
               "types" : [ "administrative_area_level_1", "political" ]
            },
                           :
                           :

Let’s see how it works in Exploratory.

Import Data

I’m going to use the same data as I used in the previous article. If you already have it, please skip this section. 

If you don’t have the data yet, here I prepared data about the major flood events in Japan since 1985. It is originally from Dartmouth Flood Observatory’s Global Archive of Large Flood Events. Download the EDF file by choosing “Download EDF” menu.

Import the downloaded EDF data by clicking ‘+’ icon next to the “Data Frames” and choosing “File Data”.

You can quickly check how the data looks like by clicking “Table” tab. Each row of the data represents a single flood event with date, damage, and where it happened with longitude/latitude data. If you followed the previous article, you should also have “prefecture” column too. In that case, remove the “prefecture” column by removing the step.

Create R Function for Reverse Geocoding with Google Map API

I’m going to create an R function that takes longitudes/latitudes and returns the prefecture names using Google Maps APIs.

Click the “+” button right next to the “Script”. Name it “find_pref2”.

Here is the R script.

#
# find_pref2: A function to find prefecture names for 
# the long/lat combinations using Google Maps API
#
find_pref2 <- function(long, lat, apiKey = NULL) {

  # Request URL parameters
  parameters <- ""

  # Add API Key in the parameters if available.
  if (!is.null(apiKey)) {
    parameters <- str_c("&key=", apiKey)
  }
    
  # Construct Google Maps APIs request URL.
  apiRequests <- iconv(str_c("https://maps.googleapis.com/maps/api/geocode/json?latlng=", lat, ",", long, parameters), "", "UTF-8")
    
  # Prefecture names will be stored to this.
  result <- c()
    
  # Iterate longitude/latitude combinations.
  for(i in 1:length(lat)) {
    
    # Avoid calling API too often.
    Sys.sleep(0.1)
        
    # Call Google Maps API.
    conn <- httr::GET(URLencode(apiRequests[i]))
        
    # Parse the JSON response. 
    apiResponse <- jsonlite::fromJSON(httr::content(conn, "text"))
        
    # Look at the address_components of the 1st address.
    ac <- apiResponse$results$address_components[[1]]
        
    # Prefecture name
    prefecture <- ""
        
    # If address_components is available, look for 
    # the prefecture name. 
    if (!is.null(ac)) {
        
      # Iterate the types of the current address_components.
      for (j in 1:length(ac$types)) {
            
        # Look for the administrative_area_level_1 in 
        # types of the address_components. In case of Japan, 
        # prefecture = administrative_area_level_1.  
        if (ac$types[[j]][[1]] == "administrative_area_level_1") {
          
          # If we find the prefecture address_components, 
          # pick the long_name and save it. 
          prefecture <- ac$long_name[[j]]
        }
      }
    }    
    result[i] <- prefecture
  }
  # Return the result vector.
  return(result)
}

It defines a function called “find_pref2”. It takes longitude/latitude data and returns the prefecture names. What the function does is,

  1. It constructs and calls the Google Maps APIs for each of the given longitude/latitude combinations. Note that we call Sys.sleep(0.1) between API requests in order to avoid hitting the 50 requests/sec limitation on Google Maps APIs.  
  2. It checks each result from the Google Maps APIs to look for the prefecture name. First, it looks at the 1st address object, then it looks into the address object to look for an address_components object that contains the prefecture information. If it finds, use the long name for the prefecture name. If it doesn’t find, uses an empty string instead.
  3. Returns the list of prefecture names corresponding to the longitude/latitude combinations as a result.

Anyway, just copy the above script and paste it into the editor, and click Save button at the right hand side top. Make sure you see the message “The script has been validated and saved successfully” at the bottom.

Use the registered R function

Now, let’s run the Reverse Geocoding function that has just been created above.

Go back to the data frame, click the ‘+’ button and choose “Create Calculation (Mutate)”.

Choose “Create New Column”, type in prefecture at the New Column Name and find_pref2(longitude, latitude) at the Calculation. This means that we’ll create a new column called “prefecture” which will have the result of find_pref2() function. Click “Run” button if it looks ok.

If you have a Google Maps API key, you can pass it to find_pres2 function like following (Replace YOUR_GOOGLE_MAPS_API_KEY to your actual key). In my experience, it work more stable with using API key. You can register and get the API key at Google Maps APIs, and you can use it for free up to the free daily quota (2,500 requests per day, as of 3/23/2018). Please see the Google Maps APIs for more detail.

If it goes well, you will see a new column “prefecture” with the prefecture names for each flood event.

We can visualize this data with Map quickly. Click “Viz” tab and select “Map -Long/Lat”. Assign “prefecture” column at the “Label”, then hover any of the dots. Now you see the prefecture name of the dot along with longitude/latitude information at the right hand side top.

Take a look at the location on the small island that we couldn’t capture the address with the GeoJSON file before. We can see that it successfully capture the information.

Even for the locations outside Japan, we get the right information now.


Reverse Geocoding by using Google Maps APIs is a powerful solution because of the accuracy and flexibility as we see above. Also, you can even capture not only the prefecture information, but also the city name, zip code and even the street address if you want. But, there are some drawbacks.

One of them is the performance. Since you need to call the REST API for each longitude/latitude combination, it can be very slow depending on the network speed. On the other hand, the reverse Geocoding with GeoJSON file is really fast because once you load the GeoJSON data, the rest of the process runs locally.

Another problem is that there is a hard limit on number of times we can call Google Maps APIs per day. If you have a large data set, you may need to register and use your API key as I mentioned, or even need to pay for more data.

Anyway, now you have two options for the reverse Geocoding, one is using GeoJSON, other one is using Google Maps APIs. Pick and use the one that works for your needs.

Happy Reverse Geocoding!


Try it for yourself!

If you want to try this out quickly, you can download the data from here, import it in Exploratory Desktop, and follow the steps.

If you don’t have Exploratory Desktop yet, you can sign up from here for 30 days free trial.


Learn Data Science without Programming

If you are interested in learning various powerful Data Science methods ranging from Machine Learning, Statistics, Data Visualization, and Data Wrangling without programming, go visit our Booster Training home page and enroll today!