Creating Vector PMTiles with Tippecanoe

Introduction

Traditionally, maps are created from image tiles. An image tile contains all the map information prerendered in an image (png). One image tile looks like:

To request information from the map (like getting the attributes of a road), a request to a server is needed to obtain the information. To change the style of the map (like changing the colors or labels) all the tiles need to be processed again on the server.

An alternative approach is to use vector tiles. Vector tiles contain all the geometries and metadata like road and place names in a compact, structured format. Vector tiles have important advantages over raster tiles:

– Styling: Map style can be adjusted dynamically on the client;

– Querying: Attribute information is stored within the vector tile so there is no need to request a server for more information;

– Smooth interactions: .Because all  map data is loaded in the map client, you can re-render the map quickly, enabling smooth zooming, tilt, and rotation;

– Size and speed: Vector tiles are really small, enabling global high resolution maps, fast map loads and efficient caching.

One popular command line tool to create vector tiles is Tippecanoe, originally developed by MapBox. At the moment, the tool is developed at Felt https://github.com/felt/tippecanoe .

Let’s figure out how to create vector tiles with Tippecanoe. We’ll use a dataset of all the railroad tracks of the world as input data.

Download data

First download the data (a 14 MB zipped shapefile)and convert it to GeoJSON (66MB):

$ wget https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_railroads.zip
$ unzip ne_10m_railroads.zip
$ ogr2ogr -f GeoJSON ne_10m_railroads.geojson ne_10m_railroads.shp

In QGIS the GeoJSON looks like:

image

There are some railroad attributes like multitrack, electric and category.

Install Tippecanoe

Now we’ve to install Tippecanoe to create the vector tiles. I’ll use Docker to build and run from the latest source code.

$ git clone https://github.com/felt/tippecanoe.git
$ cd tippecanoe
$ docker build -t tippecanoe:latest .
$ docker run tippecanoe:latest tippecanoe --version
tippecanoe v2.17.0

So Tippecanoe v2.17.0 is installed now. Let’s run it on the GeoJSON file:

$ docker run -it --rm -v D:\gisdata\naturalearth\railroads:/data tippecanoe:latest tippecanoe --output=/data/railroads.pmtiles /data/ne_10m_railroads.geojson --maximum-zoom=7 --force
For layer 0, using name "ne_10m_railroads"
25413 features, 5506888 bytes of geometry, 368 bytes of separate metadata, 167062 bytes of string pool
  99.9%  7/23/47
  100.0%  7/69/31

In this command we created a 6 MB PMTile file for zoom levels with maximum 7. A PMTile (https://github.com/protomaps/PMTiles)  is a single-file archive format for pyramids of tiled data. A PMTiles archive can be hosted on a storage platform like S3, and enables low-cost, zero-maintenance map applications.

A vector tile can contain multiple layers. To create mutiplayer layers in Tippecanoe add multiple GeoJSON files to the tippecanoe command:

$ tippecanoe file1.geojson file2.geojson 

Visualize

We can visualize the PMTile file in https://protomaps.github.io/PMTiles/?url=https%3A%2F%2Fbertt.github.io%2Fopendata%2Fworld%2Frailroads%2Frailroads.pmtiles#map=1.28/18.4/14.6 :

image

On the ‘Metadata’ tab we see there is one layer created with name ‘ne_10m_railroads’: image

On the ‘Tile inspector’ tab we see all the vector tiles created:

image

To visualize the railroads from the PMTile file in Leaflet:

<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"/>
        https://unpkg.com/leaflet@1.7.1/dist/leaflet.js
        https://unpkg.com/leaflet-hash@0.2.1/leaflet-hash.js
        https://unpkg.com/protomaps@latest/dist/protomaps.min.js
        <style>
            body, #map {
                height:100vh;
                margin:0px;
    		background: black;
            }
        </style>
    </head>
    <body>
        <div id="map"></div> 
        <script>
            const map = L.map('map')
            let hash = new L.Hash(map)
  	    if (!window.location.hash) map.setView(new L.LatLng(52.091320,5.627747),8)
            let paint_rules = [
              {
                dataLayer:"ne_10m_railroads",
                symbolizer:new protomaps.LineSymbolizer({color:"#999999"})
              }
	    ];
            var layer = protomaps.leafletLayer({url:'railroads.pmtiles', paint_rules:paint_rules})
            layer.addTo(map)
            layer.addInspector(map)
        </script>
    </body>
</html>

Result looks like:

image

For a live demo see https://bertt.github.io/opendata/world/railroads

Conclusion

In this blog we created in a few easy steps vector tiles from shapefile of worldwide railroads in PMTile format using Tippecanoe, and deployed to a standard webserver. No complicated backend WMS/WFS mapservers  are needed anymore to get this working.

2 thoughts on “Creating Vector PMTiles with Tippecanoe

Leave a comment