Sunday, September 4, 2011

Example #18 - Google Maps API

Google provides a number of APIs to use their map services.  The web services API, documented on this page,  includes geocoding.  Geocoding converts a street address to a latitude and a longitude.  That lat/long pair can be used to do SODA geoqueries or place markers on a map.

getgeo - geocode using Google Map API
getgeo takes an address as input and outputs the latitude and longitude.  Optionally, with the verbose argument, you can also output all the info that Google returns.  Take a look at that.  It might be useful to your app.  You  get back the standardized name for the street, city, state, and country plus zip code, neighborhood name.

Code
#
#  getgeo - Returns the geocode for a street address. Uses Google Maps API.
#           Outputs either latitude/longitude or all geocoding information
#
#  example: python getgeo.py "2400 West Fullerton,Chicago,IL"
#           python getgeo.py "2400 west fullerton,chicago,il" -v
#
#  args:    <street address> - must be street, city, state and comma-separated
#              and in quotes.
#           -v - verbose.  Will prettyprint all the information Google API returns
#
from urllib import urlencode, quote_plus
from urllib2 import urlopen, HTTPError, URLError
from json import load
import sys
import pprint

# constants used to index into addr[]
street = 0
city = 1
state = 2

if len(sys.argv) < 2:
    sys.stderr.write("Usage: python %s \"<street,city,state>\" [-v]\n" % sys.argv[0])
    raise SystemExit(1)

# addr will have [<street>, <city>, <state>]
addr = sys.argv[1].split(',')

if len(addr) != 3:
    sys.stderr.write("Usage: python %s \"<street,city,state>\" [-v]\n" % sys.argv[0])
    raise SystemExit(1)

verbose = False
if len(sys.argv) == 3:
    if sys.argv[2] == "-v":
        verbose = True
    else:
        sys.stderr.write("%s is an unknown argument.\n" % sys.argv[2])
        raise SystemExit(1)

url =  "http://maps.googleapis.com/maps/api/geocode/json?address=" + \
       quote_plus(addr[street]) + ',' + \
       quote_plus(addr[city])   + ',' + \
       quote_plus(addr[state])  + \
       "&sensor=false"

try:
    u = urlopen(url)
except HTTPError, e:
    print 'The server could not handle the request and returned the HTTP error code: ', e.code
    print 'The server returned the following error information:'
    print e.read()
except URLError, e:
    print 'We failed to reach a server and the URL error reason is: ', e.reason
else:
    response = load(u)

    # Check that Google sent back valid data.  If so, print lat and long.
    if response['status'] == 'OK':
        print "%s %s" % (response['results'][0]['geometry']['location']['lat'],
                     response['results'][0]['geometry']['location']['lng'])
        # otherwise, print the error Google returned and use verbose to show all other info
    else:
        sys.stderr.write("Google returned an error code: %s\n" % response['status'])
        verbose = True        # turn on verbose to help with debugging

    if verbose:
        pp = pprint.PrettyPrinter(indent=4)
        pp.pprint(response)


Output

Create a static Google map with markers
You can use the lat/longs from the datasets or a filtered result to build your own map.  There is a Google API documented on this page, to specify the characteristics of a map, add markers, and display it.

The following example gives you an idea of what you could do with Example #17's pothole results.  This code builds a map with two markers.  The first one, I called it the center marker, has the lat/long of 2400 W. Fullerton.  It's the center of the circle of potholes.  The second one, represents the pothole at 2400 W. Medill.  I arbitrarily made the center marker blue with a label of C and the pothole marker green with a label of P.

Code
The program sets up all the map variables, constructs the URL, and asks the operating system to start up your default browser with the URL.

import os, urllib

urlMapAPI = "http://maps.googleapis.com/maps/api/staticmap"
mapCenterLat = "41.9249"
mapCenterLong = "-87.6876"
mapZoomLevel = "14"
mapHeight = "512"
mapWidth = "512"
mapType = "roadmap"
centerMarkerColor = "blue"
centerMarkerLabel = "C"
mapMarkerColor = "green"
mapMarkerLabel = "P"
mapMarkerLat = "41.9240"
mapMarkerLong = "-87.6876"


url = \
    urlMapAPI + '?' + \
    'center=' + mapCenterLat + ',' + mapCenterLong + \
    '&' + \
    'size=' + mapHeight + 'x' + mapWidth + \
    '&' + \
    'maptype=' + mapType + \
    '&' + \
    'sensor=false' + \
    '&' + \
    'markers=color:' + centerMarkerColor + '%7C' + 'label:' + centerMarkerLabel + '%7C' + mapCenterLat + ',' + mapCenterLong + \
    '&' + \
    'markers=color:' + mapMarkerColor + '%7C' + 'label:' + mapMarkerLabel + '%7C' + mapMarkerLat + ',' + mapMarkerLong

os.startfile(url)

Output

This gives you an idea of how you might build a map URL dynamically with a number of markers and then have it displayed.  There are many other parameters to specify the map.  See the Google site for possibilities.

Summary
This was a side trip away from the Socrata platform and API.  Google has useful APIs that you can use for an app that involves locations.  The utility program, geocode.py, can translate an address into latitude and longitude.  You can use it for experimenting and testing or pull out pieces to add to your app.

The second example was the minimal code needed to generate a static Google map.  This starts to open up the possibilities you have for displaying locations.

No comments:

Post a Comment