A couple years ago we got iPhones, and one of my favorite apps is the RunKeeper app, which tracks your outdoor activities using the phone’s built-in GPS. When I first started using it I compared the results of the tracks from the phone to a Garmin eTrex, and they were so close that I’ve given up carrying the Garmin. The fact that the phone is always with me, makes keeping track of all my walks with Nika, and trips to work on my bicycle or skis pretty easy. Just like having a camera with you all the time means you capture a lot more images of daily life, having a GPS with you means you have the opportunity to keep much better track of where you go.
RunKeeper records locations on your phone and transfers the data to the RunKeeper web site when you get home (or during your trip if you’ve got a good enough cell signal). Once on the web site, you can look at the tracks on a Google map, and RunKeeper generates all kinds of statistics on your travels. You can also download the data as GPX files, which is what I’m working with here.
The GPX files are processed by a Python script that inserts each point into a spatially-enabled PostgreSQL database (PostGIS), and ties it to a track.
Summary views allow me to generate statistics like this, a summary of all my travels in 2010:
Another cool thing I can do is use R to generate a map showing where I’ve spent the most time. That’s what’s shown in the image on the right. If you’re familiar at all with the west side of the Goldstream Valley, you’ll be able to identify the roads, Creek, and trails I’ve been on in the last two years. The scale bar is the number of GPS coordinates fell within that grid, and you can get a sense of where I’ve travelled most. I’m just starting to learn what R can do with spatial data, so this is a pretty crude “analysis,” but here’s how I did it (in R):
library(RPostgreSQL) library(spatstat) drv <- dbDriver("PostgreSQL") con <- dbConnect(drv, dbname="new_gps", host="nsyn") points <- dbGetQuery(con, "SELECT type, ST_X(ST_Transform(the_geom, 32606)) AS x, ST_Y(ST_Transform(the_geom, 32606)) AS y FROM points INNER JOIN tracks USING (track_id) INNER JOIN types USING (type_id) WHERE ST_Y(the_geom) > 60 AND ST_X(the_geom) > -148;" ) points_ppp <- ppp(points$x, points$y, c(min(points$x), max(points$x)), c(min(points$y), max(points$y))) Lab.palette <- colorRampPalette(c("blue", "magenta", "red", "yellow", "white"), bias=2, space="Lab") spatstat.options(npixel = c(500, 500)) map <- pixellate(points_ppp) png("loc_map.png", width = 700, height = 600) image(map, col = Lab.palette(256), main = "Gridded location counts") dev.off()
Here’s a similar map showing just my walks with Nika and Piper:
And here's something similar using ggplot2:
library(ggplot2) m <- ggplot(data = points, aes(x = x, y = y)) + stat_density2d(geom = "tile", aes(fill = ..density..), contour = FALSE) m + scale_fill_gradient2(low = "white", mid = "blue", high = "red", midpoint = 5e-07)
I trimmed off the legend and axis labels: