Suffix

Published by Simon Schoeters

Rendering GPS logs in Ruby

For a little while now I want to plot my own GPS logs (like my last cycling trip). I am obsessed with geolocation.

Sure, you can use Google Maps, the default weapon of choice these days. With their API you can plot your track log on top of their maps and satellite images. You don't even have to program that, Google Maps can render KML files out of the box and there are tons of tools out there to do the same. But I'm a programmer, loading KML files in Google is no fun. I want to learn to plot my own stuff and here is how.

Plan of attack

Obviously you'll need some kind of source data to start with. I keep all my logs as a GPX file but you can use whatever format you like as you'll have to parse it never the less. You can use the cross-platform open source tool GPSBabel to convert between different formats.

Secondly we also need some kind of rendering library. I went with gnuplot as there is a Ruby binding for that one, more on this later. You'll need to install gnuplot if you don't have it yet.

Code

The gnuplot program expects tabular data in a tab separated format so our first step is to convert our source document to a gnuplot readable format. For this I parse the GPX file with Nokogiri (an XML parser):

#!/usr/bin/env ruby
require 'rubygems'
require 'nokogiri'
require 'gnuplot'
doc = Nokogiri::XML(open("your_file.gpx"))
x = doc.xpath('//xmlns:trkpt/@lon').map{|pt| pt.to_s.to_f}
y = doc.xpath('//xmlns:trkpt/@lat').map{|pt| pt.to_s.to_f}

It loads the GPX source file (which is an XML document after all) and extracts all the coordinates with XPath. We now have two arrays, one with the latitudes an the other with the longitudes.

Plotting

We can now pass our 2 data sets to gnuplot. It has no notion of spatial data so it will just link the points. Therefor we'll need to tell gnuplot to use the same scale on both the X- and Y-axis or our plotted path will be distorted (gnuplot tries to auto scale it by default).

Gnuplot.open do |gp|
  Gnuplot::Plot.new(gp) do |plot|
    plot.arbitrary_lines << "set size square"
    plot.data << Gnuplot::DataSet.new([x, y]) do |ds|
      ds.with = "lines"
      ds.notitle
    end
  end
end

Got it? That's the basic stuff, you can now play around with the gnuplot options to change colors, add a grid, change the line widths, etc.

Conclusion

gnuplot is a graphing library, it's great in drawing all kinds of graphs... it's not that great in rendering spatial data. If you know a better way to plot coordinates please leave a comment.

I'm not a GIS expert. This approach is way too simplified and will only work for shorter distances. If you are building something serious you may want to look at map projections, dilution of precision and the like.

The full - unfinished - script is available at GitHub.