Generate street maps from Google's real-time taxi-mapping service.
One of the first Google Map Hacks was released by Google itself. The Google Ride Finder is ostensibly a mapping service to find nearby taxis and airport shuttles in major metro areas. While it's useless for getting a ride with these centrally booked services, it really functions as a very engaging advertisement for these companies. (And, while we're at it, don't we actually need the public transit Google Maps Hacks extended for live updates for sustainable transport alternatives?)
The real appeal is how Google Ride Finder demonstrates the use of realtime, updating spatial data. The immediacy of the Web, combined with geo visualization, has powerful possibilities. In this hack, that live data will be repurposed to reveal the street map "ghost" of airport shuttles and taxis, producing raw data that might be consumed by grassroots mapping projects such as OpenStreetMap (http://www.openstreetmap.org/).
The Google Ride Finder lives at http://labs.google.com/ridefinder. The initial view shown in Figure 4-26 is of North America, with push pins marking the areas for which they have data.
Figure 4-26. Ride Finder home page
If you zoom in to Chicago, you'll get a view like Figure 4-27. Each pushpin represents an individual vehicle, almost all of them taxicabs.
4.13.1. Finding the Data
Like Google Local searches, Google Ride Finder receives its annotations in their geodata format. To find the location of this feed, look in the JavaScript file http://labs.google.com/ridefinder/data?file=ride_js, referenced from the HTML source. The Update Vehicle Locations button calls refreshMarkers(), which then calls updateMarkers(). This function constructs the following URL:
var j="/ridefinder/data?marker=1&lat="+f+"&lon="+g+"&z="+m+ "&src="books/2/367/1/html/2/+w+"¬es="+(new Date()).getTime();
Figure 4-27. Ride Finder in Chicago
In this bit of code, f and g are the lat/long center of the map, m is the zoom level, and w is hardcoded to 3. The notes argument is a timestamp, which seems to be appended to avoid hitting any cache. Constructing a URL with, for example, the center of Manhattan and scale 8, confirms that this is the feed for Ride Finder.
http://labs.google.com/ridefinder/data?marker=1&lat=40.750422 &lon=-73.996328&z=8&src=3¬es=
Although each annotation within the feed corresponds to the location of an individual vehicle, no unique identifier is included to link two annotations across an update. It's possible to get near-matches by measuring spatial proximity in successive feeds, which update every five minutes according to Google. The interested reader is invited to give it a try and and see if you can build a poor man's real-time traffic monitoring application.
4.13.2. Accumulating the Data
Here, we're going to accumulate taxi positions over a few days and build up a street map of the city of your choice. Set the latitude and longitude of the data URL, derived from another source, such as http://geocoder.us/. Setting zoom to 8 is sufficient to cover a metro region. Append the current timestamp to avoid the cache.
Paste the following code into a file called accumulate.pl:
#!/usr/bin/perl $dir = "."; $date = time; $lat = 40.750422; $lon = 73.996328; $url = " http://labs.google.com/ridefinder/data?" . "marker=1&lat=$lat&lon=$lon&z=8&src=1¬es=$date"; system("/usr/bin/wget P $dir $url");
The variable $dir specifies where you will store the location data files. For example, ~/data will store them in the subdirectory named data/ under your home directory. You want the script to run every five minutes in order to collect data. You can obsessively watch the clock and start the script yourself, or, under a *nix variant, you can use the scheduling feature of the modern operating system. Edit your crontab with the command crontab e. This line will run the script every five minutes.
0-59/5 * * * * /home/ride_finder/accumulate.pl
Change /home/ride_finder to match the directory in which you installed the accumulate.pl script.
4.13.3. Plotting the Data
After about 24 hours, you'll have enough data to start building ghost maps. This Perl script, draw.pl, simply strips the lat/long from the standard input and plots the points as an unprojected map. You'll also need the Image::Magick module from the CPAN, which you can find at http://search.cpan.org/~jchristy/PerlMagick/.
#!/usr/bin/perl use Math::Trig qw(deg2rad rad2deg asin); use Image::Magick; use POSIX qw(floor); $lat = 40.750422; $lon = -73.996328; $d = 20; $w = 1500; $h = 1500; sub latlon2xy { my ($lat,$lon) = @_; my @xy; $xy[1] = $h * ($north - $lat) / ($north - $south); $xy[0] = $w * ($lon - $west) / ($east - $west); return @xy; } $radius = 6378.1; #km $lat = deg2rad($lat); $lon = deg2rad($lon); $arc = $d / $radius; $north = rad2deg($lat + $arc); $south = rad2deg($lat - $arc); $west = rad2deg ($lon+asin(-1*sin($arc)/cos( asin(sin($lat)*cos($arc)) ))); $east = rad2deg ($lon+asin( sin($arc)/cos( asin(sin($lat)*cos($arc)) ))); my $img = new Image::Magick->new(size=> $w . "x" . $h, quality=> '100'); $img->ReadImage('xc:white'); while (<>) { @points = split "= 0 && $xy[0] <= $w && $xy[1] >= 0 && $xy[1] <= $h) { $img->Set('pixel[' . floor($xy[0]) . ',' . floor($xy[1]) . ']'=>'#f00'); } } } $img->Write(filename=>"out.jpg");
In order to run the hack, we'll assume you have the script in the current directory and the data you accumulated earlier in a subdirectory called data/. From there, run:
$ perl draw.pl data/*
The script writes the result to an image called out.jpg in the current directory. Set variables within the script for the lat/long center of the data feed, and a distance in kilometers of your choosing, which are used to calculate the extents of the map, and the width and height of the image. You want the lat/long to be close to the same as you selected in accumulate.pl. With lat/long translated to x/y coordinates, ImageMagick is employed to plot each point.
At first you may see just the barest outline of the city, with some major roads and bridges perhaps. With more days of data, individual streets will begin to form along lines of highest density, as suggested by Figure 4-28. (GPS in these vehicles can be inaccurate, resulting in a distribution over the actual street location, possibly bleeding into off-street space and buildings.) Peculiarities of taxi travel will become apparent, with routes to the airport overemphasized and route variations along socioeconomic and districting lines. Maybe you can spot drivers' favorite places for a coffee break.
Figure 4-28. Ghost roads of New York
4.13.4. Hacking the Hack
For a neat variation, build an animated GIF with ImageMagick by grouping points by the hour, gradually revealing the street map ghost. Have fun!
4.13.5. See Also
Mikel Maron
You Are Here: Introducing Google Maps
Introducing the Google Maps API
Mashing Up Google Maps
On the Road with Google Maps
Google Maps in Words and Pictures
API Tips and Tricks
Extreme Google Maps Hacks