Offline map tiles in QGIS

Participatory Mapping Station

I was invited to run a station at a DiscoTech event sponsored by the Detroit Digital Justice Coalition (DDJC). DiscoTechs are community technology fairs, and are a really great model for sharing tech knowledge within and across communities. The DDJC has released a zine with stories and bootstrap practices so other groups can run their own DiscoTech events. While previous events had been held in somewhat central locations, this DiscoTech was held at a community center in the 48217 neighborhood at the edge of Detroit and home to a strong community of environmental justice activists who are part of the DDJC.

However, the recreation center where the event was located didn’t have Internet access. This posed a bit of a problem for our station, as we wanted to have people both create analog maps of their community using paper and transparency sheets with dry-erase markers, and digital ones. I chose Quantum GIS (QGIS) as the tool to make digital maps, because it could work on my notebook without any Internet connection. I’ve used the excellent OpenLayers QGIS Plugin to provide slippy map tiles from Open Street Map as a layer in QGIS, but this wouldn’t work without an Internet connection. My solution was to essentially run a full mapping stack on my notebook computer. This was surprisingly straightforward, and helped me better understand how the pieces of a modern custom mapping stack work together.

Make your tiles

First, I had to get the raw data from which to generate my tiles. I grabbed an extract of the Detroit Metro Area from the OpenStreetMap Metro Extracts page since we were just making maps of Detroit and selecting a subset of the map data would save a lot of time when rendering the tiles.

There are lots of ways to make map tiles, but TileMill is pretty easy to use, and very powerful. MapBox, the makers of TileMill also provide a template project called OSM Bright, which they describe as “a sensible starting point for quickly making beautiful maps in TileMill based on an OpenStreetMap database.” To get a basic set of tiles for Detroit, I just followed the OSM Bright quickstart tutorial to generate the tiles I needed.

TileMill lets you export your tiles in a number of different formats, but I chose the MBTiles format because I liked the idea of all of my tiles being packaged in a single file. It just seemed more portable in case I wanted to move my project to a separate machine.

Serve your tiles

There are also many different ways to serve your custom tiles. This tutorial provides a good rundown of one method of building a server, using Mapnik to generate the tiles. However, I wanted something really lightweight, and something that would use tiles in the MBTiles format. I found TileStache, which I liked because it was written in Python, had its own built-in webserver, and supported MBTiles. Because it supports a wide variety of datasources, the configuration seemed a bit daunting at first, but was ultimately pretty simple, at least for using an MBTiles tileset.


This is what my tilestache.xml looked like:


And this is what my tilestache.cfg (the file that configures the datasource) looked like:

  "cache": {"name": "Test"},
  "layers": {
    "detroit": {
      "provider": {
        "name": "mbtiles",
        "tileset": "detroit2.mbtiles"

Add your tiles as a layer in QGIS

Update: I originally hacked the OpenLayers plugin as described below, but Nathan and David Forest pointed out in the comments that there’s a less hacky way.

GDAL > 1.7.0 supports the Tiled Map Service (TMS) format that we’re serving using to serve our tiles in Tilestache.  You can create a VRT file as described in this blog post, How to display OpenStreetMap data tiles with no plugin inside Qgis and add your tiles as a raster layer.

Hack the OpenLayers QGIS Plugin

The last step is to get the QGIS OpenLayers Plugin to use my local tileserver instead of grabbing them from the OSM tile server over the web. There’s definitely more elegant ways of doing this, but I needed to get this to work fast, so I simply edited the osm.html file that is part of the plugin. On my system, this file was located at ~/.qgis/python/plugins/openlayers/html/osm.html. I edited the file so that around line 33 of the file

, I replaced the tile URL string “${z}/${x}/${y}.png” with “${z}/${x}/${y}.png”, the ServerUrl directive from my tilestache.xml.

After editing this file and starting QGIS, I was able to choose “Add OpenStreetMap layer” from the “Plugins > OpenLayers plugin” menu in QGIS to add a base layer of my custom tileset.