Mapping NextBus locations

Now, we are ready to use this information to create our own map. The best source of freely available street mapping data is the OpenStreetMap (OSM) project: http://www.openstreetmap.org.

OSM also has a publicly available REST API called StaticMapLite to create static map images: http://staticmap.openstreetmap.de.

The OSM StaticMapLite API provides you with a GET API based on Google's static map API to create simple map images with a limited number of point markers and lines. A GET API, as opposed to REST, allows you to append name/value parameter pairs after a question mark on the URL. A REST API makes the parameters part of the URL path. We'll use the API to create our own NextBus API map on demand with a red pushpin icon for the bus location.

In the next example, we have condensed the previous script down to a compact function named nextbus(). The nextbus() function accepts an agency, route, command, and epoch as arguments. The command defaults to vehicleLocations, and the epoch defaults to 0 to get the last 15 minutes of data. In this script, we'll pass in the LA route 2 route information and use the default command that returns the most recent latitude/longitude of the bus.

We have a second function named nextmap() that creates a map with a blue dot on the current location of the bus each time it is called. The map is created by building a GET URL for the OSM StaticMapLite API, which centers on the location of the bus and uses a zoom level between 1-18 and map size to determine the map extent. You can access the API directly in a browser to see an example of what the nextmap() function does: http://staticmap.openstreetmap.de/staticmap.php?center=40.714728,-73.998672&zoom=14&size=865x512&maptype=mapnik&markers=40.702147,-74.015794,lightblue1|40.711614,-74.012318,lightblue2|40.718217,-73.998284,lightblue3

The nextmap() function accepts a NextBus agency ID, route ID, and string for the base image name of the map. The function calls the nextbus() function to get the latitude/longitude pair. The execution of this program loops through at timed intervals, creates a map on the first pass, and then overwrites the map on subsequent passes. The program also outputs a timestamp each time a map is saved. The requests variable specifies the number of passes and the freq variable represents the time in seconds between each loop:

import urllib.request
import urllib.parse
import urllib.error
from xml.dom import minidom
import time


def nextbus(a, r, c="vehicleLocations", e=0):
    """Returns the most recent latitude and
    longitude of the selected bus line using
    the NextBus API (nbapi)
    Arguments: a=agency, r=route, c=command,
    e=epoch timestamp for start date of track,
    0 = the last 15 minutes
    """
    nbapi = "http://webservices.nextbus.com"
    nbapi += "/service/publicXMLFeed?"
    nbapi += "command={}&a={}&r={}&t={}".format(c, a, r, e)
    xml = minidom.parse(urllib.request.urlopen(nbapi))
    # If more than one vehicle, just get the first  
    bus = xml.getElementsByTagName("vehicle")[0]
    if bus:  
        at = bus.attributes
        return(at["lat"].value, at["lon"].value)
    else:
        return (False, False)


def nextmap(a, r, mapimg):
    """Plots a nextbus location on a map image
    and saves it to disk using the OpenStreetMap
    Static Map API (osmapi)"""
    # Fetch the latest bus location
    lat, lon = nextbus(a, r)
    if not lat:
        return False
    # Base url + service path
    osmapi = "http://staticmap.openstreetmap.de/staticmap.php?"
    # Center the map around the bus location
    osmapi += "center={},{}&".format(lat, lon)
    # Set the zoom level (between 1-18, higher=lower scale)
    osmapi += "zoom=14&"
    # Set the map image size
    osmapi += "&size=865x512&"
    # Use the mapnik rendering image
    osmapi += "maptype=mapnik&"
    # Use a red, pushpin marker to pin point the bus
    osmapi += "markers={},{},red-pushpin".format(lat, lon)
    img = urllib.request.urlopen(osmapi)
    # Save the map image
    with open("{}.png".format(mapimg), "wb") as f:
        f.write(img.read())
    return True

# Nextbus API agency and bus line variables
agency = "lametro"
route = "2"

# Name of map image to save as PNG
nextimg = "nextmap"

# Number of updates we want to make
requests = 3

# How often we want to update (seconds)
freq = 5

# Map the bus location every few seconds
for i in range(requests):
    success = nextmap(agency, route, nextimg)
    if not success:
        print("No data available.")
        continue
    print("Saved map {} at {}".format(i, time.asctime()))
    time.sleep(freq)

While the script runs, you'll see an output similar to the following, showing at what time the script saved each map:

Saved map 0 at Sun Nov  1 22:35:17 2015
Saved map 1 at Sun Nov  1 22:35:24 2015
Saved map 2 at Sun Nov  1 22:35:32 2015

This script saves a map image similar to the following screenshot, depending on where the bus was when you ran it:

Mapping NextBus locations

This map is an excellent example of using an API to create a custom mapping product. However, it is a very basic tracking application. To begin to develop it into a more interesting geospatial product, we need to combine it with some other real-time data source that gives us more situational awareness.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset