Very Simple Google Mapping with Ruby

Josh Stillman
4 min readNov 27, 2017

--

For our Module 1 final project, Jon Wu and I made a command-line application that allows users to analyze CitiBike’s published monthly trip data. Using Active Record and three models — Station, Trip, and Bike — our program allowed users to ask questions like, “What was the most popular bike station overall this month?,” “What was the most popular trip for female subscribers this month?”, and “What was the longest trip taken this month (and how much was the late fee)?”

State of the art graphics.

Using our Bike and Trip models in Active Record, we built an option that allows users to see the most ridden bike that month, along with a list of each trip that was taken with that bike. We nicknamed this popular bike, “Billy the Bicycle”.

Lots o’ trips for Billy the Bicycle

We had a long wish list of additional features that we considered building, but but we only had a couple of days to construct version 1.0. So, for this blog post, I returned to our program and built one of those wish list features: a visual representation of Billy the Bicycle’s many trips.

Billy’s favorite tunes.

We thought it would be cool to visually display all of the trips that the most-ridden bike took on Google maps. Turns out it is pretty easy to do so using Google Maps Directions URLs. CitiBike’s monthly data provides the latitude/longitude of the starting and ending stations for all trips taken each month, including for each trip taken by Billy the Bicycle. Those latitude/longitude coordinates can be placed into a URL sent to Google Maps in the following format:

https://www.google.com/maps/dir/?api=1&parameters

The relevant parameters that must be placed into the URL areorigin, waypoints, destination, and travelmode.

Theorigin and destinationparameters point to latitude/longitude coordinates separated by a comma. Commas must URL escaped and replaced with %2C. For example:

&origin=40.8013434%2C-73.97114574&destination=40.795%2C-73.9645 

Between origin and destination, Google Maps allows us to include up to nine intermediate stops, called waypoints. Each waypoint is again represented by comma-separated latitude/longitude coordinates. Each waypoint is also separated by a | character, URL escaped as %7C. For example, three waypoints would look like:

&waypoints=40.72079821%2C-73.95484712%7C40.77140426%2C-73.9535166%7C40.7284186%2C-73.98713956

Last, we specify that our travelmode is by bicycle. Citibike’s data only shows the the starting and ending stations for each of Billy’s trips, and doesn’t show the actual route taken between those stations. But we can use Google Maps’ biking directions feature to reconstruct what that rider’s route may have looked like. At the end of our URL, let’s add:

&travelmode=bicycling

The final URL will look like:

https://www.google.com/maps/dir/?api=1&origin=40.74144387%2C-73.97536082&waypoints=40.74854862%2C-73.98808416%7C40.76019252%
2C-73.9912551%7C40.74144387%2C-73.97536082%7C40.74854862%2C-73.98808416%7C40.73454567%2C-73.99074142%7C40.74444921%2C-73.983
03529%7C40.733812191966315%2C-73.98054420948029%7C40.73912601%2C-73.97973776%7C40.73704984%2C-73.99009296%7C40.74334935%2C-7
4.00681753%7C&destination=40.72165481%2C-74.00234737&travelmode=bicycling
Cat Hi-Five!

Now let’s construct our Google Maps URL based on the trips taken by Billy the Bicycle. We’ll do so in a function called map_bike_trips that we’ll call when the user asks to see the most ridden bike.

First, we’ll use Active Record and our Bike, Station, and Trip models that we built previously to find the most ridden bike’s ID:

#Find most ridden bike IDbike_id =  Trip.group("city_bike_id").order("count(*)DESC").first.city_bike_id

Then, we’ll build up an array of the first eleven trips taken by Billy (Google Maps URLs supports a maximum of eleven locations). We’ll start by finding Billy’s trips, ordering them chronologically by start_time, and collecting the first eleven trips’ starting station coordinates in alocations array.

locations = []Bike.find_by(city_bike_id: bike_id).trips.order("start_time").first(11).each do |trip|
locations << trip.start_station.latitude.to_s + "%2C" + trip.start_station.longitude.to_s
end

Next, we’ll start building up our maps_url. We’ll start the URL off with our origin:

maps_url = https://www.google.com/maps/dir/?api=1&origin=" + locations[0] + "&waypoints="

Then we’ll add nine waypoints by iterating from the second to the penultimate element in the locations array:

(1..locations.size-2).each do |i|
maps_url << locations[i] + "%7C"
end

Last, we’ll add the destination and travelmode:

maps_url << "&destination=" + locations.last + "&travelmode=bicycling"

Now that we have constructed the complete URL, we can open it in the user’s default browser by calling the system "open" command. The URL must be wrapped in quotes for this to work correctly:

system "open '#{maps_url}'"

Putting it all together, our map_bike_trips function looks like:

def map_bike_trips  #Find the most ridden bike's ID:  bike_id = Trip.group("city_bike_id").order("count(*) DESC").first.city_bike_id  #For each of that bike's first 11 trips, find the starting station's
#coordinates, then add them to the locations array:
locations = [] Bike.find_by(city_bike_id: bike_id).trips.order("start_time").first(11).each do |trip|
locations << trip.start_station.latitude.to_s + "%2C" + trip.start_station.longitude.to_s
end
#Start building up the URL with the origin:

maps_url = "https://www.google.com/maps/dir/?api=1&origin=" + locations[0] + "&waypoints="

#Then, for the waypoints, add in the second through penultimate
#coordinate pairs, correctly formatted:
(1..locations.size-2).each do |i|
maps_url << locations[i] + "%7C"
end
#Last, add the destination and travel mode to the URL: maps_url << "&destination=" + locations.last + "&travelmode=bicycling" #Finally, open the URL we built in the user's default browser. system "open '#{maps_url}'"end

When map_bike_trips is called, it shows Billy the Bicycle’s first eleven trips on Google Maps:

Billy’s been a busy bicycle.

Hooray! Now you know how to do some very basic Google Mapping using Ruby. Happy mapping!

Give yourself a pat on the back, friend.

--

--