A Ruby Gem for GTFS to GeoJSON Conversion

I published my first Ruby gem: gtfs-geojson! You can view the source on GitHub. gtfs-geojson is a Ruby utility to convert a GTFS feed to a GeoJSON file. It’s a simple endeavor, for sure, but I’m pleased with what I learned along the way.

Let’s start out with some before-and-after views of the data. These images were created using QGIS, OpenStreetMap, Transfort’s GTFS feed, and the gtfs-geojson library.

The Transfort GTFS data loaded in QGIS before applying the Ruby gem for GTFS to GeoJSON conversion.

This map displays the shapes.txt file from Transfort's GTFS feed loaded into QGIS. The seemingly-inconsistent shading on the lines is because there are no lines at all; each "line" is made up of a sequence of points. Each point contains a route ID and is ordered relative to the other points in its route by a point sequence value.

The Transfort GTFS data loaded in QGIS after applying the Ruby gem for GTFS to GeoJSON conversion.

After running the GTFS feed through gtfs-geojson, you now have a GeoJSON file whose features are each route from the original feed. I used "Categorized" styles in QGIS to quickly apply a unique color to each route.

As with most transit projects, the input to gtfs-geojson is a GTFS feed. GTFS is the standard format published by transit agencies worldwide to make their routes, stops, and even fares usable by developers. The data is a series of comma-separated text files. To validate a GTFS feed, I used an existing gem. gtfs will fail gracefully if the shapes.txt file is not present, which is the only file I actually need for the conversion to GeoJSON.

gtfs-geojson implements the same algorithm as the “Points to path” QGIS tool I used when looking at Transfort bus data. The main trick is that the points within each route ID must be sorted by their point sequence value. Several other QGIS plugins I tried did not do this correctly, so don’t forget this if implementing this yourself!

While QGIS tools output shapefiles, gtfs-geojson produces a GeoJSON file, which is a JSON stream with geospatial points and polylines data served up in a standard format. I have previously loaded GeoJSON files in Mapbox applications, and they are also useful in a GIS context. The following three lines will load the library, validate the GTFS feed, convert its shapes.txt file to GeoJSON format, and write the GeoJSON to a file.

require 'gtfs-geojson'
geojson = GTFS::GeoJSON.generate("gtfs.zip")
File.open("gtfs.geojson",'w') do { |f| f.write(geojson) }

That’s it! Let me know if you have any suggestions! The README on the GitHub repo gives installation instructions.

The most valuable tip I learned while creating this gem was the use of the $RUBYLIB environment variable. This isn’t necessary when installing a gem onto your system using bundler, but it is extremely helpful during development. $RUBYLIB lets you specify the path searched when the require keyword is used. To add paths dynamically to $RUBYLIB, you can push items to the $: array. $: is shorthand for $LOAD_PATH within a Ruby program. My require_relative days are over!

If you are considering writing your own gem, I highly recommend RubyGems.org’s “Make Your Own Gem” guide. It is comprehensive and just generally fantastic.

I plan to use gtfs-geojson in a Rails project in the future. And speaking of gems, I’ve also been dabbling on a Ruby API client for Transitland. I hope to have more to share on both fronts soon!

Until then, ride on!

Have any transit projects to share? Let me know!

Written on March 22, 2016