Suffix

Rendering GPS logs in Ruby

Plotting a GPS log as a SVG image with Ruby.

I would like to plot my GPS logs from my last cycling trip.

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. As a programmer, loading KML files in Google is no fun. I want to learn to plot my own stuff.

Plotted GPS log

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. Therefore 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. Please, let me know if you know a better way to plot coordinates.

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.