TIPPECANOE(1)
β¨ tippecanoe(1) β¨
okay so bestie, welcome to tippecanoe β the manual page, but make it make sense π
This bad boy builds vector tilesets (read: https://github.com/mapbox/vector-tile-spec/) from large (or small) collections of GeoJSON (http://geojson.org/), FlatGeobuf (https://github.com/flatgeobuf/flatgeobuf), or CSV (https://en.wikipedia.org/wiki/Comma-separated_values) features β like the ones in MADE_WITH.md.
This is the official home of Tippecanoe, developed and actively maintained by Erica Fischer (https://github.com/e-n-f) at Felt (https://felt.com).
Wanna self-hosted, API-driven version? Contact a technical sales engineer at sales@felt.com. Felt produces highly performant, automatically projected versions of your data, and utilizes a rendering engine, built on top of MapLibre GL JS (https://github.com/maplibre/maplibre-gl-js), to style vector and raster data. slay π
Version 2.0.0 is equivalent to 1.36.0 (https://github.com/mapbox/tippecanoe/tree/1.36.0) in the original repository. Thank you Mapbox for the many years of early support π«Ά
πΈ INTENT πΈ
The goal of Tippecanoe is lowkey iconic: it enables making a scale-independent view of your data, so that at any level β from the entire world down to a single building β you can see the density and texture of the data, rather than a simplification from dropping supposedly unimportant features, or clustering, or aggregating them. no cap.
- Give it all of OpenStreetMap and zoom out? It should hand you back something that looks like "All Streets" (http://benfry.com/allstreets/map5.html) rather than something that looks like an Interstate road atlas. π
- Give it all the building footprints in Los Angeles and zoom out far enough that most individual buildings are no longer discernible? You should still be able to see the extent and variety of development in every neighborhood β not just the largest downtown buildings. π
- Give it a collection of years of tweet locations? You should be able to see the shape and relative popularity of every point of interest and every significant travel corridor. β¨
π INSTALLATION π
The easiest way to install tippecanoe on OSX is with Homebrew (http://brew.sh/):
$ brew install tippecanoe
On Ubuntu it will usually be easiest to build from the source repository:
$ git clone https://github.com/felt/tippecanoe.git
$ cd tippecanoe
$ make -j
$ make install
See Development (#development) below for how to upgrade your C++ compiler or install prerequisite packages if you get compiler errors. bestie, we've all been there π
π USAGE π
$ tippecanoe -o file.mbtiles [options] [file.json file.json.gz file.fgb ...]
If no files are specified, it reads GeoJSON from the standard input. If multiple files are specified, each is placed in its own layer (#input-files-and-layer-names). one layer per file, main character energy.
The GeoJSON features need not be wrapped in a FeatureCollection. You can concatenate multiple GeoJSON features or files together, and it will parse out the features and ignore whatever other objects it encounters. it literally does not care about the extra stuff π¦
β TRY THIS FIRST β
If you aren't sure what options to use, try this:
$ tippecanoe -zg -o out.mbtiles --drop-densest-as-needed in.geojson
The -zg option will make Tippecanoe choose a maximum zoom level that should be high enough to reflect the precision of the original data. (If it turns out still not to be as detailed as you want, use -z manually with a higher number.)
If the tiles come out too big, the --drop-densest-as-needed option will make Tippecanoe try dropping what should be the least visible features at each zoom level. (If it drops too many features, use -x to leave out some feature attributes that you didn't really need.) fr fr π
π EXAMPLES π
Create a tileset of TIGER roads for Alameda County, to zoom level 13, with a custom layer name and description:
$ tippecanoe -o alameda.mbtiles -l alameda -n "Alameda County from TIGER" -z13 tl_2014_06001_roads.json
Create a tileset of all TIGER roads, at only zoom level 12, but with higher detail than normal, with a custom layer name and description, and leaving out the LINEARID and RTTYP attributes:
$ cat tiger/tl_2014_*_roads.json | tippecanoe -o tiger.mbtiles -l roads -n "All TIGER roads, one zoom" -z12 -Z12 -d14 -x LINEARID -x RTTYP
π³ COOKBOOK π³
okay bestie this is the part where we actually cook. these are real recipes for real datasets, all of them tested, all of them slay. copy-paste energy. let's go π
πΈ Linear features (world railroads), visible at all zoom levels
curl -L -O 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
then the actual magic:
tippecanoe -zg -o ne_10m_railroads.mbtiles --drop-densest-as-needed --extend-zooms-if-still-dropping ne_10m_railroads.geojson
and here's what each of those flags is doing, because i know you wanna know:
-zgβ Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature--drop-densest-as-neededβ If the tiles are too big at low zoom levels, drop the least-visible features to allow tiles to be created with those features that remain--extend-zooms-if-still-droppingβ If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
π¦ Discontinuous polygon features (buildings of Rhode Island), visible at all zoom levels
curl -L -O https://usbuildingdata.blob.core.windows.net/usbuildings-v1-1/RhodeIsland.zip
unzip RhodeIsland.zip
tippecanoe -zg -o RhodeIsland.mbtiles --drop-densest-as-needed --extend-zooms-if-still-dropping RhodeIsland.geojson
the flag breakdown, and watch this because one of these descriptions is slightly different from the railroads one, no cap:
-zgβ Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature--drop-densest-as-neededβ If the tiles are too big at low or medium zoom levels, drop the least-visible features to allow tiles to be created with those features that remain--extend-zooms-if-still-droppingβ If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
π Continuous polygon features (states and provinces), visible at all zoom levels
curl -L -O https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_1_states_provinces.zip
unzip -o ne_10m_admin_1_states_provinces.zip
ogr2ogr -f GeoJSON ne_10m_admin_1_states_provinces.geojson ne_10m_admin_1_states_provinces.shp
tippecanoe -zg -o ne_10m_admin_1_states_provinces.mbtiles --coalesce-densest-as-needed --extend-zooms-if-still-dropping ne_10m_admin_1_states_provinces.geojson
-zgβ Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature--coalesce-densest-as-neededβ If the tiles are too big at low or medium zoom levels, merge as many features together as are necessary to allow tiles to be created with those features that are still distinguished--extend-zooms-if-still-droppingβ If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
note the coalesce instead of drop β with continuous stuff you merge, you don't yeet. periodt.
π Large point dataset (GPS bus locations), for visualization at all zoom levels
curl -L -O ftp://avl-data.sfmta.com/avl_data/avl_raw/sfmtaAVLRawData01012013.csv
sed 's/PREDICTABLE.*/PREDICTABLE/' sfmtaAVLRawData01012013.csv > sfmta.csv
tippecanoe -zg -o sfmta.mbtiles --drop-densest-as-needed --extend-zooms-if-still-dropping sfmta.csv
(The sed line is to clean the corrupt CSV header, which contains the wrong number of fields.)
like, it's giving "the data is a little broken and we're fixing it with one line of sed." iconic.
-zgβ Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature--drop-densest-as-neededβ If the tiles are too big at low or medium zoom levels, drop the least-visible features to allow tiles to be created with those features that remain--extend-zooms-if-still-droppingβ If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
π Clustered points (world cities), summing the clustered population, visible at all zoom levels
curl -L -O https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_populated_places.zip
unzip -o ne_10m_populated_places.zip
ogr2ogr -f GeoJSON ne_10m_populated_places.geojson ne_10m_populated_places.shp
tippecanoe -zg -o ne_10m_populated_places.mbtiles -r1 --cluster-distance=10 --accumulate-attribute=POP_MAX:sum ne_10m_populated_places.geojson
-zgβ Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature-r1β Do not automatically drop a fraction of points at low zoom levels, since clustering will be used instead--cluster-distance=10β Cluster together features that are closer than about 10 pixels from each other--accumulate-attribute=POP_MAX:sumβ Sum thePOP_MAX(population) attribute in features that are clustered together. Other attributes will be arbitrarily taken from the first feature in the cluster.
okay the way that --accumulate-attribute=POP_MAX:sum just adds up whole cities' worth of people when they get smooshed into one cluster?? we love math π
π Show countries at low zoom levels but states at higher zoom levels
two datasets, two tilesets, one tile-join, one flawless finale:
curl -L -O https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_0_countries.zip
unzip ne_10m_admin_0_countries.zip
ogr2ogr -f GeoJSON ne_10m_admin_0_countries.geojson ne_10m_admin_0_countries.shp
curl -L -O https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_1_states_provinces.zip
unzip -o ne_10m_admin_1_states_provinces.zip
ogr2ogr -f GeoJSON ne_10m_admin_1_states_provinces.geojson ne_10m_admin_1_states_provinces.shp
tippecanoe -z3 -o countries-z3.mbtiles --coalesce-densest-as-needed ne_10m_admin_0_countries.geojson
tippecanoe -zg -Z4 -o states-Z4.mbtiles --coalesce-densest-as-needed --extend-zooms-if-still-dropping ne_10m_admin_1_states_provinces.geojson
tile-join -o states-countries.mbtiles countries-z3.mbtiles states-Z4.mbtiles
Countries:
-z3β Only generate zoom levels 0 through 3--coalesce-densest-as-neededβ If the tiles are too big at low or medium zoom levels, merge as many features together as are necessary to allow tiles to be created with those features that are still distinguished
States and Provinces:
-Z4β Only generate zoom levels 4 and beyond-zgβ Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature--coalesce-densest-as-neededβ If the tiles are too big at low or medium zoom levels, merge as many features together as are necessary to allow tiles to be created with those features that are still distinguished--extend-zooms-if-still-droppingβ If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
see how -z3 and -Z4 are like... the β¨chosen onesβ¨ that split the zoom range between them so nothing overlaps? main character energy on both sides fr fr.
π Represent multiple sources (Illinois and Indiana counties) as separate layers
curl -L -O https://www2.census.gov/geo/tiger/TIGER2010/COUNTY/2010/tl_2010_17_county10.zip
unzip tl_2010_17_county10.zip
ogr2ogr -f GeoJSON tl_2010_17_county10.geojson tl_2010_17_county10.shp
curl -L -O https://www2.census.gov/geo/tiger/TIGER2010/COUNTY/2010/tl_2010_18_county10.zip
unzip tl_2010_18_county10.zip
ogr2ogr -f GeoJSON tl_2010_18_county10.geojson tl_2010_18_county10.shp
tippecanoe -zg -o counties-separate.mbtiles --coalesce-densest-as-needed --extend-zooms-if-still-dropping tl_2010_17_county10.geojson tl_2010_18_county10.geojson
-zgβ Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature--coalesce-densest-as-neededβ If the tiles are too big at low or medium zoom levels, merge as many features together as are necessary to allow tiles to be created with those features that are still distinguished--extend-zooms-if-still-droppingβ If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
two input files, no -l, so each source keeps its own layer. separate but together. situationship goals honestly.
π Merge multiple sources (Illinois and Indiana counties) into the same layer
curl -L -O https://www2.census.gov/geo/tiger/TIGER2010/COUNTY/2010/tl_2010_17_county10.zip
unzip tl_2010_17_county10.zip
ogr2ogr -f GeoJSON tl_2010_17_county10.geojson tl_2010_17_county10.shp
curl -L -O https://www2.census.gov/geo/tiger/TIGER2010/COUNTY/2010/tl_2010_18_county10.zip
unzip tl_2010_18_county10.zip
ogr2ogr -f GeoJSON tl_2010_18_county10.geojson tl_2010_18_county10.shp
tippecanoe -zg -o counties-merged.mbtiles -l counties --coalesce-densest-as-needed --extend-zooms-if-still-dropping tl_2010_17_county10.geojson tl_2010_18_county10.geojson
As above, but
-l countiesβ Specify the layer name instead of letting it be derived from the source file names
one -l and suddenly they're all in the same layer. besties sharing a room π«Ά
β Selectively remove and replace features (Census tracts) to update a tileset
this one is the glow-up recipe. we take a tileset, yeet one county out of it, and drop the newer version in its place:
# Retrieve and tile California 2000 Census tracts
curl -L -O https://www2.census.gov/geo/tiger/TIGER2010/TRACT/2000/tl_2010_06_tract00.zip
unzip tl_2010_06_tract00.zip
ogr2ogr -f GeoJSON tl_2010_06_tract00.shp.json tl_2010_06_tract00.shp
tippecanoe -z11 -o tracts.mbtiles -l tracts tl_2010_06_tract00.shp.json
# Create a copy of the tileset, minus Alameda County (FIPS code 001)
tile-join -j '{"*":["none",["==","COUNTYFP00","001"]]}' -f -o tracts-filtered.mbtiles tracts.mbtiles
# Retrieve and tile Alameda County Census tracts for 2010
curl -L -O https://www2.census.gov/geo/tiger/TIGER2010/TRACT/2010/tl_2010_06001_tract10.zip
unzip tl_2010_06001_tract10.zip
ogr2ogr -f GeoJSON tl_2010_06001_tract10.shp.json tl_2010_06001_tract10.shp
tippecanoe -z11 -o tracts-added.mbtiles -l tracts tl_2010_06001_tract10.shp.json
# Merge the filtered tileset and the tileset of new tracts into a final tileset
tile-join -o tracts-final.mbtiles tracts-filtered.mbtiles tracts-added.mbtiles
The -z11 option explicitly specifies the maxzoom, to make sure both the old and new tilesets have the same zoom range.
The -j option to tile-join specifies a filter, so that only the desired features will be copied to the new tileset. This filter excludes (using none) any features whose FIPS code (COUNTYFP00) is the code for Alameda County (001).
lowkey obsessed with howtile-join -j '{"*":["none",["==","COUNTYFP00","001"]]}'is just a tiny JSON bouncer at the door going "not you, 001." π and then-flets it overwrite the output file without throwing a fit.
and that's the move: filter out the old, add in the new, join them back together. flawless. a whole tileset refresh with zero drama β well, zero drama after you get the zoom ranges matching, iykyk.
β¨ OPTIONS β¨
okay bestie, deep breath π there are a LOT of options here. like, a concerning amount. but the tea is: most of the time you're gonna ignore basically all of them except -o output.mbtiles to name your output file, and probably -f to delete the file that already exists with that name. that's it. that's the whole vibe. π
not sure what the right maxzoom is for your data? no thoughts head empty? that's fine, -zg will guess one for you based on the density of features. she's psychic bestie π¦
here's the thing tho: Tippecanoe will normally drop a fraction of point features at zooms below the maxzoom, so your low-zoom tiles don't get all bloated and huge. so:
- got a smallish data set where literally every point would fit without dropping any of them? use
-r1to keep them all. no point left behind π - want point dropping BUT you still want the tiles denser than
-zgthinks they should be? use-Bto set a basezoom lower than the maxzoom. you're the main character, you decide.
if some of your tiles are still coming out too big in spite of all the settings above, you'll often want --drop-densest-as-needed β it drops whatever fraction of the features is necessary at each zoom level to make that zoom level's tiles actually work. lowkey a lifesaver π
if your features have a lot of attributes, use -y to keep only the ones you really need. declutter, it's giving minimalism π§
and if your input is newline-delimited GeoJSON, use -P and watch input parsing get so much faster. zoom zoom β
π¦ Output tileset
-o file.mbtiles,file.pmtilesor--output=file.mbtilesβ Name the output file. β¨-e directoryor--output-to-directory=directoryβ Write tiles to the specified directory instead of to an mbtiles file.-for--forceβ Delete the mbtiles file if it already exists instead of giving an error-For--allow-existingβ Proceed (without deleting existing data) if the metadata or tiles table already exists or if metadata fields can't be set. You probably don't want to use this. π
okay real talk on -F: they said "probably don't want to use this" and they MEANT it bestie. proceed with caution π
π·οΈ Tileset description and attribution
-n nameor--name=nameβ Human-readable name for the tileset (defaultfile.json)-A textor--attribution=textβ Attribution (HTML) to be shown with maps that use data from this tileset.-N descriptionor--description=descriptionβ Description for the tileset (defaultfile.mbtiles)
π Input files and layer names
name.jsonorname.geojsonβ Read the named GeoJSON input file into a layer called name.name.json.gzorname.geojson.gzβ Read the named gzipped GeoJSON input file into a layer called name.name.fgbβ Read the named FlatGeobuf input file into a layer called name.name.csvβ Read the named CSV input file into a layer called name.-l nameor--layer=nameβ Use the specified layer name instead of deriving a name from the input filename or output tileset. If there are multiple input files specified, the files are all merged into the single named layer, even if they try to specify individual names with-L.-L name:file.jsonor--named-layer=name:file.jsonβ Specify layer names for individual files. If your shell supports it, you can use a subshell redirect like-L name:<(cat dir/*.json)to specify a layer name for the output of streamed input. π-L{layer-json}or--named-layer={layer-json}β Specify an input file and layer options by a JSON object. The JSON object must contain a"file"key to specify the filename to read from. (If the"file"key is an empty string, it means to read from the standard input stream.) It may also contain a"layer"field to specify the name of the layer, and/or a"description"field to specify the layer's description in the tileset metadata, and/or a"format"field to specifycsvorfgbfile format if it is not obvious from the name. Example:
tippecanoe -z5 -o world.mbtiles -L'{"file":"ne_10m_admin_0_countries.json", "layer":"countries", "description":"Natural Earth countries"}'
CSV input files currently support only Point geometries, from columns named latitude, longitude, lat, lon, long, lng, x, or y. so if you were hoping for fancy polygons in your CSV... no π
π§΅ Parallel processing of input
-Por--read-parallelβ Use multiple threads to read different parts of each GeoJSON input file at once. This will only work if the input is line-delimited JSON with each Feature on its own line, because it knows nothing of the top-level structure around the Features. Spurious"EOF"error messages may result otherwise. Performance will be better if the input is a named file that can be mapped into memory rather than a stream that can only be read sequentially.
if the input file begins with the RFC 8142 record separator (https://tools.ietf.org/html/rfc8142), parallel processing of input will be invoked automatically, splitting at record separators rather than at all newlines. β¨
Parallel processing will also be automatic if the input file is in FlatGeobuf format. she just does it herself, iconic π
π Projection of input
-s projectionor--projection=projectionβ Specify the projection of the input data. Currently supported areEPSG:4326(WGS84, the default) andEPSG:3857(Web Mercator). In general you should use WGS84 for your input files if at all possible.
π Zoom levels
-z zoomor--maximum-zoom=zoomβ Maxzoom: the highest zoom level for which tiles are generated (default 14)-zgor--maximum-zoom=gβ Guess what is probably a reasonable maxzoom based on the spacing of features.--smallest-maximum-zoom-guess=zoomβ Guess what is probably a reasonable maxzoom based on the spacing of features, but using the specified zoom if a lower maxzoom is guessed. If-Bgis also set, the base zoom will be set to the guessed maxzoom, with all the points carried forward into additional zooms through the one specified.-Z zoomor--minimum-zoom=zoomβ Minzoom: the lowest zoom level for which tiles are generated (default 0)-aeor--extend-zooms-if-still-droppingβ Increase the maxzoom if features are still being dropped at that zoom level. The detail and simplification options that ordinarily apply only to the maximum zoom level will apply both to the originally specified maximum zoom and to any levels added beyond that.--extend-zooms-if-still-dropping-maximum=countβ Increase the maxzoom if features are still being dropped at that zoom level by up to count zoom levels.-ator--generate-variable-depth-tile-pyramidβ Don't produce child tiles for any tile that should be sufficient to be overzoomed to any higher zoom level. Such tiles will be produced with maximum detail and no simplification or polygon cleaning. Tiles with point features below the basezoom or where any features have to be dropped dynamically, or which contain too many features or bytes with full detail, will be written out with normal detail and split into child tiles. Tilesets generated with this option are suitable for use only with tile servers that will find the appropriate tile to overzoom from and will simplify and clean the geometries appropriately before serving the tile.
fr fr on that last one, bestie β that's a hard requirement, not a suggestion. if your tile server isn't doing the overzooming homework, this option is not for you π
-R zoom/x/yor--one-tile=zoom/x/yβ Set the minzoom and maxzoom to zoom and produce only the single specified tile at that zoom level. just one lil tile. a single serving π
Okay so real talk: if you already know the exact precision you want your data at, or the map scale of the printed map you're matching, this table is gonna be your new roman empire π it shows the approximate precision and scale you get from the various -z options when you're using the default -d detail of 12:
-z0β precision32000 ft,10000 m, map scale1:320,000,000-z1β precision16000 ft,5000 m, map scale1:160,000,000-z2β precision8000 ft,2500 m, map scale1:80,000,000-z3β precision4000 ft,1250 m, map scale1:40,000,000-z4β precision2000 ft,600 m, map scale1:20,000,000-z5β precision1000 ft,300 m, map scale1:10,000,000-z6β precision500 ft,150 m, map scale1:5,000,000-z7β precision250 ft,80 m, map scale1:2,500,000-z8β precision125 ft,40 m, map scale1:1,250,000-z9β precision64 ft,20 m, map scale1:640,000-z10β precision32 ft,10 m, map scale1:320,000-z11β precision16 ft,5 m, map scale1:160,000-z12β precision8 ft,2 m, map scale1:80,000-z13β precision4 ft,1 m, map scale1:40,000-z14β precision2 ft,0.5 m, map scale1:20,000-z15β precision1 ft,0.25 m, map scale1:10,000-z16β precision6 in,15 cm, map scale1:5000-z17β precision3 in,8 cm, map scale1:2500-z18β precision1.5 in,4 cm, map scale1:1250-z19β precision0.8 in,2 cm, map scale1:600-z20β precision0.4 in,1 cm, map scale1:300-z21β precision0.4 in,1 cm, map scale1:300-z22β precision0.4 in,1 cm, map scale1:300
β¨ Tile resolution β¨
-d detail,--full-detail=detailβ the detail at max zoom level (default12, for tile resolution of2-D detail,--low-detail=detailβ the detail at lower zoom levels (default12, for tile resolution of2-m detail,--minimum-detail=detailβ the minimum detail it'll even try if the tiles come out too big at regular detail (default7)--extra-detail=detailβ generates tiles with even more detail than the "full" detail at the max zoom level, so you can max out location precision. Heads up bestie: these tiles may not work with some rendering software that internally limits detail to12or13. The extra detail does not affect the choice of maxzoom guessing, the amount of simplification, or the "tiny polygon" threshold the way--full-detaildoes. Other than that, the tiles should look exactly like they did without it β except they'll be way more precise when overzoomed. π
All the internal math runs on a 32-bit tile coordinate system, so 1/(2 of the size of Earth, or about 1cm, is the smallest distinguishable distance. If maxzoom + detail > 32, you get no extra resolution compared to just using a smaller maxzoom or detail, and the detail of the tiles will be reduced to the max that can actually be used with the specified maxzoom. No cap.
πΈ Filtering feature attributes πΈ
-x name,--exclude=nameβ excludes the named attributes from all features. You can stack multiple-xoptions to exclude several attributes. (And pls do NOT comma-separate names inside a single-x, that's not the vibe.)-y name,--include=nameβ includes the named attributes in all features, which excludes everything you didn't explicitly name. Stack multiple-yoptions to explicitly include several attributes. (Same rule: don't comma-separate names within a single-y.)-X,--exclude-allβ excludes all the attributes and encodes only geometry. sheer minimalism, actually π¦
π Modifying feature attributes π
-Tattribute:type,--attribute-type=attribute:typeβ coerces the named feature attribute to be the type you specified. The type may bestring,float,int, orbool. If the type isbool, then original attributes of0(or, if numeric,0.0, etc.),false,null, or the empty string all becomefalse, and literally anything else becomestrue. If the type isfloatorintand the original attribute was non-numeric, it becomes0. If the type isintand the original attribute was floating-point, it gets rounded to the nearest integer. periodt.-Yattribute:description,--attribute-description=attribute:descriptionβ sets the description for the specified attribute in the tileset metadata to description, instead of the usualString,Number, orBoolean.-Eattribute:operation,--accumulate-attribute=attribute:operationβ preserves the named attribute from features that get dropped, coalesced-as-needed, or clustered π The operation may besum,product,mean,max,min,concat, orcomma, and it says how the named attribute gets accumulated onto the attribute of the same name in a feature that does survive. You can also hand these over as JSON keys and values:
--accumulate-attribute='{"attr": "operation", "attr2", "operation2"}'
--set-attribute attribute:valueβ sets the value of the specified attribute in each feature to the value you gave. This is mostly useful for giving each feature's attribute an initial value for--accumulate-attribute. The attributes and values may also be specified as JSON keys and values:
--set-attribute='{"attr": value, "attr2", value}'
-pe,--empty-csv-columns-are-nullβ treats empty CSV columns as nulls instead of as empty strings. tiny change, massive difference π-aI,--convert-stringified-ids-to-numbersβ if a feature ID is the string representation of a number, converts it to a plain number to use as the feature ID. slay β¨--use-attribute-for-id=nameβ bestie, this says "hey, use the attribute with thisnameas if it were literally the feature ID." Caution though: if that attribute is a stringified number, you also gotta pass-aIso it gets converted into an actual number. Don't skip that part, fr.-pN,--single-precisionβ writes those double-precision numeric attribute values into tiles as single-precision instead, so your tiles get smaller. cute little diet for your data π--maximum-string-attribute-length=lengthβ string attributes longer thanlengthbytes get truncated. bye bye extra characters βοΈ
πΈ Filtering features by attributes πΈ
-j filter,--feature-filter=filterβ checks every feature against a per-layer filter and only keeps the ones that match. The filter format is defined in the Mapbox GL Style Specification or in a Felt filter specification that's still to be finalized (so, slay but unstable). Any features sitting in layers where you specified no filter at all just pass straight through, untouched, no questions asked. Fun fact: filters for the layer"*"apply to all layers. And the special variable$zoomrefers to the current zoom level. π-J filter-file,--feature-filter-file=filter-fileβ same energy as-j, except the filter lives in a file instead of on your command line.
Example: to find the Natural Earth countries with low scalerank but high LABELRANK:
tippecanoe -z5 -o filtered.mbtiles -j '{ "ne_10m_admin_0_countries": [ "all", [ "<", "scalerank", 3 ], [ ">", "LABELRANK", 5 ] ] }' ne_10m_admin_0_countries.geojson
Example: to retain only major TIGER roads at low zoom levels:
tippecanoe -o roads.mbtiles -j '{ "*": [ "any", [ ">=", "$zoom", 11 ], [ "in", "MTFCC", "S1100", "S1200" ] ] }' tl_2015_06001_roads.json
Tippecanoe also accepts expressions of the form [ "attribute-filter", name, expression ], and those filter individual feature attributes instead of yeeting whole features. So like, want to drop the road names at low zoom levels? Literally just do this:
tippecanoe -o roads.mbtiles -j '{ "*": [ "attribute-filter", "FULLNAME", [ ">=", "$zoom", 9 ] ] }' tl_2015_06001_roads.json
β οΈ Heads up bestie: anattribute-filterexpression is always considered to evaluate totrueβ meaning it keeps the feature instead of dropping it. So if you wanna stack multipleattribute-filterexpressions, or mix in other expressions that remove features from the same layer, you have to wrap them all in anallexpression so every single one actually gets evaluated. Otherwise some are justβ¦ not. π
π¦ Dropping a fixed fraction of features by zoom level π¦
-r rate,--drop-rate=rateβ the rate at which dots get dropped at zoom levels below basezoom (default2.5). Use-rgand it'll guess a drop rate that keeps at most 50,000 features in the densest tile. You can also specify a marker-width with-rgwidthso fewer features survive in the densest tile (compensating for the bigger marker), or use-rfnumberto allow at mostnumberfeatures in the densest tile. And if you use-rptogether with-zgor--smallest-maximum-zoom-guess, it'll pick a drop rate from the same distance-between-features metrics that are used to choose the maxzoom. it's giving β¨adaptiveβ¨-B zoom,--base-zoom=zoomβ the base zoom, aka the level at and above which all points are included in the tiles (defaultmaxzoom). Use-Bgand it guesses a zoom level that keeps at most 50,000 features in the densest tile. You can also specify a marker-width with-Bgwidthto allow fewer features in the densest tile to compensate for the larger marker, or-Bfnumberto allow at mostnumberfeatures in the densest tile.--retain-points-multiplier=multipleβ retains the specifiedmultipleof points instead of just the number of points the drop rate would ordinarily keep. Then later you can thin them back out with the-moption totippecanoe-overzoom. The start of each cluster gets marked in the feature sequence by thetippecanoe:retain_points_multiplier_firstattribute. Oh and--tile-size-limitwill also be extended at low zoom levels to make room for all those multiplied features. no cap π--drop-denser=percentageβ when dropping dots at zoom levels below the base zoom, give the specifiedpercentagepreference to retaining points in sparse areas and dropping points in dense areas. sparse girlies stay, dense girlies go π«Ά--limit-base-zoom-to-maximum-zoom,-Pbβ limits the guessed base zoom so it never exceeds the maxzoom, even if that means putting more than the requested number of features into a base zoom tile.-al,--drop-linesβ lets that "dot" dropping at lower zooms apply to lines too.-ap,--drop-polygonsβ lets that "dot" dropping at lower zooms apply to polygons too.-K distance,--cluster-distance=distanceβ clusters points (like--cluster-densest-as-needed, but without the experimental discovery process) that are approximately withindistanceof each other. The units are tile coordinates within a nominally 256-pixel tile, so the maximum value of255allows only one feature per tile. Values around10are probably appropriate for typical marker sizes. See--cluster-densest-as-neededbelow for the behavior details.-k zoom,--cluster-maxzoom=zoomβ the max zoom on which to cluster points, if clustering is enabled.-kg,--cluster-maxzoom=gβ sets--cluster-maxzoom=tomaxzoom - 1so that literally all the features are visible at the maximum zoom level. iconic behavior π--preserve-point-density-threshold=levelβ at the low zoom levels, don't reduce point density below the specifiedlevel, even if the specified drop rate would normally call for it β this is so that low-density areas of the map don't just come out looking blank and sad. The unit is the distance between preserved points, as a fraction of the size of a tile. Values of32or64are probably appropriate for typical marker sizes.
π Dropping a fraction of features to keep under tile size limits π
-as,--drop-densest-as-neededβ if a tile is too large, it tries to shrink it to under 500K by increasing the minimum spacing between features. The discovered spacing applies to the entire zoom level.-ad,--drop-fraction-as-neededβ dynamically drops some fraction of features from each zoom level to keep large tiles under the 500K size limit. (This is like-pdbut it applies to the entire zoom level, not to each tile.)-an,--drop-smallest-as-neededβ dynamically drops the smallest features (physically smallest: the shortest lines or the smallest polygons) from each zoom level to keep large tiles under the 500K size limit.-aN,--coalesce-smallest-as-neededβ dynamically combines the smallest features (physically smallest: the shortest lines, or the smallest polygons, or the densest points) from each zoom level into other nearby features to keep large tiles under the 500K size limit. Real talk: this option will probably not help very much withLineStrings. It's mostly intended for polygons, to maintain the full original area covered by polygons while still reducing the feature count somehow. The attributes of the small polygons are not preserved into the combined features (except through--accumulate-attribute), only their geometry. And one more thing β the polygons that nested polygons get coalesced into may not necessarily be the immediately enclosing features. π«-aD,--coalesce-densest-as-neededβ dynamically combines the densest features from each zoom level into other nearby features to keep large tiles under the 500K size limit. (Again, mostly useful for polygons.)-aS,--coalesce-fraction-as-neededβ dynamically combines a fraction of features from each zoom level into other nearby features to keep large tiles under the 500K size limit. (Again, mostly useful for polygons.)-pd,--force-feature-limitβ dynamically drops some fraction of features from large tiles to keep them under the 500K size limit. It will probably look ugly at the tile boundaries, ngl. (This is like-adbut it applies to each tile individually, not to the entire zoom level.) You probably don't want to use this. like, genuinely. π-aC,--cluster-densest-as-neededβ if a tile is too large, it tries to reduce its size by increasing the minimum spacing between features and leaving one placeholder feature from each group. That surviving feature gets a"clustered": trueattribute to show it represents a cluster, a"point_count"attribute showing how many features got clustered into it, and a"sqrt_point_count"attribute showing the relative width of a feature to represent the cluster. If the features being clustered are points, the representative feature sits at the average of the original points' locations; otherwise, one of the original features is just left as the representative. main character feature energy π
π§ Dropping tightly overlapping features π§
-g gamma,--gamma=gammaβ the rate at which especially dense dots get dropped (default0, for no effect). A gamma of2reduces the number of dots less than a pixel apart down to the square root of their original number. math ate π₯-aG,--increase-gamma-as-neededβ if a tile is too large, it tries to shrink it to under 500K by increasing the-ggamma. The discovered gamma applies to the entire zoom level. You probably want to use--drop-densest-as-neededinstead. (we said what we said π )
π Line and polygon simplification π
-S scale,--simplification=scaleβ multiplies the tolerance for line and polygon simplification byscale. The standard tolerance tries to keep the line or polygon within one tile unit of its proper location. You can probably go up to about10without too much visible difference.-ps,--no-line-simplificationβ doesn't simplify lines and polygons. at all. periodt.-pS,--simplify-only-low-zoomsβ doesn't simplify lines and polygons at maxzoom (but does simplify at lower zooms).--simplification-at-maximum-zoom=scaleβ uses the specifiedscaleat maxzoom instead of the standard simplification scale (which still applies at lower zooms).-pn,--no-simplification-of-shared-nodesβ bestie, this one refuses to simplify away any node where LineStrings or Polygon rings converge, diverge, or cross. Heads up tho: it will not be effective if you also use--coalesce. In between intersection nodes, LineString segments or polygon edges get simplified identically in each feature if possible. Use this instead of--detect-shared-borders, ok?-pt,--no-tiny-polygon-reductionβ don't smoosh the area of teeny tiny polygons into small squares that represent their combined area.-pT,--no-tiny-polygon-reduction-at-maximum-zoomβ same energy as above, but it combines the area of very small polygons into small squares only at zoom levels below the maximum.--tiny-polygon-size=sizeβ set the size for tiny polygons instead of the default2. Real talk: anything above6or so will lead to visible artifacts with the default tile detail πΈ-av,--visvalingamβ use Visvalingam's simplification algorithm instead of Douglas-Peucker's. Algorithm switch-up, periodt.
π Attempts to improve shared polygon boundaries (iconic behaviour)
-ab,--detect-shared-bordersβ DEPRECATED. In the manner of TopoJSON (https://github.com/mbostock/topojson/wiki/Introduction), it detects borders shared between multiple polygons and simplifies them identically in each polygon. The catch? It takes more time and memory than just considering each polygon individually. Useno-simplification-of-shared-nodesinstead β it's faster and more correct. no cap.-aL,--grid-low-zoomsβ at all zoom levels belowmaxzoom, this snaps all lines and polygons to a stairstep grid instead of letting diagonals exist. You'll also want to specify a tile resolution, probably-D8. It gives you a way to display continuous parcel, gridded, or binned data at low zooms without drowning your tiles in tiny polygons, since features either get stretched out to the grid unit or lost entirely β depends on how they happened to be aligned in the original data. You probably don't want to use this π
π Controlling clipping to tile boundaries
-b pixels,--buffer=pixelsβ buffer size where features are duplicated from adjacent tiles. Units are "screen pixels" β that's1/256th of the tile width or height. Default is5.-pc,--no-clippingβ don't clip features to the size of the tile. If a feature overlaps the tile's bounds or buffer at all, it gets included completely. Be careful bestie: this can produce very large tilesets, especially with large polygons π-pD,--no-duplicationβ like--no-clipping, each feature is included intact instead of being cut to tile boundaries. But also: it's included only in a single tile per zoom level rather than potentially in multiple copies. Which means clients of the tileset must check adjacent tiles (possibly some distance away) to make sure they've got all the features. Yes, they have to do the work themselves π
π¦ Reordering features within each tile
-pi,--preserve-input-orderβ keeps the original input order of features as the drawing order instead of ordering them geographically. (Lowkey it's implemented as a restoration of the original order at the end, so that dot-dropping stays geographic β which means it also undoes-ao.)-ac,--coalesceβ coalesce consecutive features that have the same attributes. Super useful if you have a ton of small polygons with identical attributes and you wanna merge them together π-ao,--reorderβ reorder features so ones with the same attributes sit in sequence (instead of ones that are approximately spatially adjacent), to try to get them to coalesce. If you use--coalesce, you probably want this too.-ar,--reverseβ tries reversing the directions of lines so they coalesce and compress better. You probably don't want to use this one ngl.-ah,--hilbertβ puts features in Hilbert Curve order instead of the usual Z-Order. This improves the odds that spatially adjacent features will be sequentially adjacent, and should improve density calculations and spatial coalescing. It should be the default eventually β¨--order-by=attributeβ order features by the specified attribute, in alphabetical or numerical order. You can spec multiple--order-byand--order-descending-byoptions, and the first one is the primary sort key.--order-descending-by=attributeβ order features by the specified attribute, in reverse alphabetical or numerical order. Same deal: multiple--order-byand--order-descending-byoptions may be specified, first one is the primary sort key.--order-smallest-firstβ order features so the smallest geometry comes first in each tile. Multiple--order-byand--order-descending-byoptions may be specified, first being the primary sort key.--order-largest-firstβ order features so the largest geometry comes first in each tile. Multiple--order-byand--order-descending-byoptions may be specified, first being the primary sort key.
π Adding calculated attributes
-ag,--calculate-feature-densityβ adds a new attribute,tippecanoe_feature_density, to each feature, to record how densely features are spaced in that area of the tile. Use it in the style to produce a glowing effect where points are densely packed β¨ It can range from0in the sparsest areas to255in the densest.-ai,--generate-idsβ add anid(a feature ID, not an attribute namedid) to each feature that doesn't already have one. RN there is no guarantee that the id added will be stable between runs, or that it won't conflict with manually-assigned feature IDs. Future versions of Tippecanoe may change the mechanism for allocating IDs. iykyk.-aX,--calculate-feature-indexβ add atippecanoe:indexfield to each feature, giving its index in the quadkey or hilbert sequence.
π§ Trying to correct bad source geometry
-aw,--detect-longitude-wraparoundβ detects when consecutive points within a feature jump to the other side of the world, and tries to fix the geometry. main character energy honestly.-pw,--use-source-polygon-windingβ instead of respecting GeoJSON polygon ring order, use the original polygon winding in the source data to distinguish inner (clockwise) and outer (counterclockwise) polygon rings.-pW,--reverse-source-polygon-windingβ instead of respecting GeoJSON polygon ring order, use the opposite of the original polygon winding in the source data to distinguish inner (counterclockwise) and outer (clockwise) polygon rings.--clip-bounding-box=minlon,minlat,maxlon,maxlatβ clip all features to the specified bounding box.-aP,--convert-polygons-to-label-pointsβ replace polygon geometries with a label point or points for the polygon in each tile it intersects.
π Setting or disabling tile size limits
-M bytes,--maximum-tile-bytes=bytesβ use the specified number of bytes as the maximum compressed tile size instead of500K.-O features,--maximum-tile-features=featuresβ use the specified number of features as the maximum in a tile instead of200,000.--limit-tile-feature-count=featuresβ abruptly limit each tile to the specified number of features, after ordering them if specified.--limit-tile-feature-count-at-maximum-zoom=featuresβ abruptly limit each tile at the maximum zoom level to the specified number of features, after ordering them if specified.-pf,--no-feature-limitβ don't limit tiles to200,000features-pk,--no-tile-size-limitβ don't limit tiles to500Kbytes-pC,--no-tile-compressionβ don't compress the PBF vector tile data. If you're getting"Unimplemented type 3"error messages from a renderer, it's probably because it expects uncompressed tiles using this option rather than the normal gzip-compressed tiles π₯-pg,--no-tile-statsβ don't generate the tilestats row in the tileset metadata. Uploads without tilestats (https://github.com/mapbox/mapbox-geostats) will take longer to process.--tile-stats-attributes-limit=countβ include tilestats information about at most count attributes instead of the default1000.--tile-stats-sample-values-limit=countβ calculate tilestats attribute statistics based on count values instead of the default1000.--tile-stats-values-limit=countβ report count unique attribute values in tilestats instead of the default100.
π Temporary storage
-t directory,--temporary-directory=directoryβ put the temporary files in directory. If you don't specify, it'll use/tmp.
β Progress indicator
-q,--quietβ work quietly instead of reporting progress or warning messages π€«-Q,--no-progress-indicatorβ don't report progress, but still give warnings-U seconds,--progress-interval=secondsβ don't report progress more often than the specified number of seconds.-u,--json-progressβ like-quietbut logs progress as a JSON object. Use in combination with-U.-v,--versionβ report Tippecanoe's version number π
π Filters
-C command,--prefilter=commandβ specify a shell filter command to be run at the start of assembling each tile-c command,--postfilter=commandβ specify a shell filter command to be run at the end of assembling each tile
The pre- and post-filter commands let you do optional filtering or transformation on the features of each tile as it's created π«Ά They are shell commands, run with the zoom level, X, and Y as the $1, $2, and $3 arguments. Future versions of Tippecanoe may add additional arguments for more context.
So like β your features get handed to the filter as a whole stack of newline-delimited GeoJSON objects on standard input, and tippecanoe is sitting there, tapping its foot, expecting to read another set of GeoJSON features back from the filter's standard output. So the filter genuinely has to feed it something, bestie. Don't leave it on read. π
The prefilter gets the features at the highest resolution available β before line simplification, polygon topology repair, gamma calculation, dynamic feature dropping, or any of that other internal processing. So you're getting the tea in its completely unedited form. β¨
The postfilter gets them wayyyyy later β at tile resolution, after simplification, cleaning, and dropping. It's the final cut, basically.
The layer name comes along inside the tippecanoe element of the feature and must be passed through, or the feature won't stay in its correct layer. And for the prefilter specifically, that tippecanoe element might also carry index, sequence, extent, and dropped elements β and those have to be passed through too, for internal operations like --drop-densest-as-needed, --drop-smallest-as-needed, and --preserve-input-order to actually work. So don't drop them. Periodt. π
β¨ Examples: β¨
- Make a tileset of the Natural Earth countries to zoom level 5, and also copy the GeoJSON features to files in a
tiles/z/x/y.geojsondirectory hierarchy.
tippecanoe -o countries.mbtiles -z5 -C 'mkdir -p tiles/$1/$2; tee tiles/$1/$2/$3.geojson' ne_10m_admin_0_countries.json
- Make a tileset of the Natural Earth countries to zoom level 5, but including only those tiles that intersect the bounding box of Germany β¨https://www.flickr.com/places/info/23424829β©. (The
limit-tiles-to-bboxscript is in the Tippecanoe source directory β¨filters/limit-tiles-to-bboxβ©.)
tippecanoe -o countries.mbtiles -z5 -C './filters/limit-tiles-to-bbox 5.8662 47.2702 15.0421 55.0581 $*' ne_10m_admin_0_countries.json
- Make a tileset of TIGER roads in Tippecanoe County, leaving out all but primary and secondary roads (as classified by TIGER β¨https://www.census.gov/geo/reference/mtfcc.htmlβ©) below zoom level 11.
tippecanoe -o roads.mbtiles -c 'if [ $1 -lt 11 ]; then grep "\"MTFCC\": \"S1[12]00\""; else cat; fi' tl_2016_18157_roads.json
π Environment π
Tippecanoe normally uses as many parallel threads as the operating system claims there are CPUs available. You can override that number by setting the TIPPECANOE_MAX_THREADS environmental variable. Slay.
π¦ GeoJSON extension π¦
Tippecanoe defines a GeoJSON extension you can use to set the minimum and/or maximum zoom level at which an individual feature gets included in the vector tileset you're producing. Like, per-feature zoom control. Iconic.
If you have a feature like this:
{
"type" : "Feature",
"tippecanoe" : { "maxzoom" : 9, "minzoom" : 4 },
"properties" : { "FULLNAME" : "N Vasco Rd" },
"geometry" : {
"type" : "LineString",
"coordinates" : [ [ -121.733350, 37.767671 ], [ -121.733600, 37.767483 ], [ -121.733131, 37.766952 ] ]
}
}
...with a tippecanoe object specifying a maxzoom of 9 and a minzoom of 4, then the feature will only appear in the vector tiles for zoom levels 4 through 9. Note that the tippecanoe object belongs to the Feature, not to its properties. If you specify a minzoom for a feature, it will be preserved down to that zoom level even if dot-dropping with -r would otherwise have dropped it. The feature said "I'm staying," and it meant it. π«Ά
You can also specify a layer name in the tippecanoe object, and it will take precedence over the filename or the name specified using --layer, like this:
{
"type" : "Feature",
"tippecanoe" : { "layer" : "streets" },
"properties" : { "FULLNAME" : "N Vasco Rd" },
"geometry" : {
"type" : "LineString",
"coordinates" : [ [ -121.733350, 37.767671 ], [ -121.733600, 37.767483 ], [ -121.733131, 37.766952 ] ]
}
}
If your source GeoJSON only has minzoom, maxzoom and/or layer within properties, you can use ndjson-cli β¨https://github.com/mbostock/ndjson-cli/blob/master/README.mdβ© to move them into the required tippecanoe object by piping the GeoJSON like this:
ndjson-map 'd.tippecanoe = { minzoom: d.properties.minzoom, maxzoom: d.properties.maxzoom, layer: d.properties.layer }, delete d.properties.minzoom, delete d.properties.maxzoom, delete d.properties.layer, d'
βοΈ Geometric simplifications βοΈ
At every zoom level, line and polygon features get subjected to Douglas-Peucker simplification to the resolution of the tile. That's just the vibe, it's giving efficient.
For point features, it drops 1/2.5 of the dots for each zoom level above the point base zoom (which is normally the same as the -z max zoom, but can be a different zoom specified with -B if you have precise but sparse data). I don't know why 2.5 is the appropriate number, but the densities of many different data sets fall off at about this same rate. You can use -r to specify a different rate. π
You can use the gamma option to thin out especially dense clusters of points. For any area where dots are closer than one pixel together (at whatever zoom level), a gamma of 3, for example, will reduce these clusters to the cube root of their original density. Math is math.
For line features, it drops any features that are too small to draw at all. This still leaves the lower zooms too dark (and too dense for the 500K tile limit, in some places), so I need to figure out an equitable way to throw features away. π
Unless you specify --no-tiny-polygon-reduction, any polygons that are smaller than a minimum area (currently 4 square subpixels) will have their probability diffused, so that some of them will be drawn as a square of this minimum size and others will not be drawn at all β preserving the total area that all of them should have had together. Cute AND mathematically balanced. π
Features in the same tile that share the same type and attributes are coalesced together into a single geometry if you use --coalesce. You are strongly encouraged to use -x to exclude any unnecessary attributes to reduce wasted file size. Do it. Your tilesets will thank you.
If a tile is larger than 500K, it will try encoding that tile at progressively lower resolutions before failing if it still doesn't fit.
π οΈ Development π οΈ
Requires sqlite3 and zlib (should already be installed on MacOS). Rebuilding the manpage uses md2man (gem install md2man).
Linux:
sudo apt-get install gcc g++ make libsqlite3-dev zlib1g-dev
Then build:
make
and perhaps
make install
Tippecanoe now requires features from the 2011 C++ standard. If your compiler is older than that, you will need to install a newer one. On MacOS, updating to the latest XCode should get you a new enough version of clang++. On Linux, you should be able to upgrade g++ with:
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
sudo apt-get update -y
sudo apt-get install -y g++-5
export CXX=g++-5
π³ Docker Image π³
A tippecanoe Docker image can be built from source and executed as a task to automatically install dependencies and allow tippecanoe to run on any system supported by Docker. Main character energy, honestly.
$ docker build -t tippecanoe:latest .
$ docker run -it --rm \
-v /tiledata:/data \
tippecanoe:latest \
tippecanoe --output=/data/output.mbtiles /data/example.geojson
The commands above will build a Docker image from the source and compile the latest version. The image supports all tippecanoe flags and options. π
π Examples π
Check out some examples of maps made with tippecanoe β¨MADE_WITH.mdβ©
π Name π
The name is a joking reference β¨http://en.wikipedia.org/wiki/Tippecanoe_and_Tyler_Tooβ© to a "tiler" for making map tiles. Iykyk. πβ¨
π tile-join π
Okay bestie, meet tile-join π β the tool that copies and merges vector mbtiles files, and also glues fresh attributes from a CSV file onto the features already living inside them.
Here's the vibe: it reads the tiles out of an existing .mbtiles file, a .pmtiles file, or a directory of tiles, matches them up against the records in the CSV (only if you gave it one, no pressure), and writes out a whole new tileset. Slay. β¨
And listen β if you hand it multiple source mbtiles files or multiple source tile directories, it reads all of them and writes their combined contents into the new mbtiles output. If they define the same layers or the same tiles? Merged. Periodt. π
The options are:
π¦ Output tileset
-o out.mbtiles,out.pmtilesor--output=out.mbtilesβ write the new tiles to the specified.mbtilesfile πΎ-e directoryor--output-to-directory=directoryβ write the new tiles into the specified directory instead of into an mbtiles file π-for--forceβ removeout.mbtilesif it already exists (yes, it will just delete it, be so serious) π₯-ror--read-fromβ list of input mbtiles to read from π₯
π Overzooming
--overzoomβ if one of the source tilesets has a bigger maxzoom than the others, scale up the tiles from the tilesets with the lower maxzooms so they all end up with the same maxzoom in the output tileset π--buffer=pixelsor-b pixelsβ set the size of the tile buffer in the overzoomed tiles π§΄
π·οΈ Tileset description and attribution
-A attributionor--attribution=attributionβ set the attribution string π-n nameor--name=nameβ set the tileset name β¨-N descriptionor--description=descriptionβ set the tileset description π¬
π§ Layer filtering and naming
-l layeror--layer=layerβ include the named layer in the output. You can drop multiple-loptions to keep multiple layers. Don't specify any? They all get retained. Generous queen π-L layeror--exclude-layer=layerβ remove the named layer from the output. Multiple-Loptions remove multiple layers π«-Rold:newor--rename-layer=old:newβ rename the layer called old to be called new instead. Multiple-Roptions rename multiple layers. Heads up: renaming happens before filtering, iykyk π- Zoom levels
-z zoomor--maximum-zoom=zoomβ don't copy tiles from zoom levels higher than the specified zoom β¬οΈ-Z zoomor--minimum-zoom=zoomβ don't copy tiles from zoom levels lower than the specified zoom β¬οΈ
𧬠Merging attributes from a CSV file
-c match.csvor--csv=match.csvβ usematch.csvas the source of the new attributes to join onto the features. First line of the file should be the key names, the rest of the lines are values. First column is the one that gets matched against the existing features; the other columns are the new data getting added π
π― Filtering features and feature attributes
-x keyor--exclude=keyβ remove the attributes named key from the output. Use this to ditch the field you were matching against once you don't need it anymore after the join, or to remove literally any other attribute you're over. Multiple-xoptions remove multiple attributes π-Xor--exclude-allβ remove all attributes from the output π-y keyor--include=keyβ remove every attribute except the ones named key from the output. Multiple-yoptions retain multiple attributes π«Ά-ior--if-matchedβ only include features that matched the CSV π―-j filteror--feature-filter=filterβ check features against a per-layer filter (as defined in the Mapbox GL Style Specification athttps://docs.mapbox.com/mapbox-gl-js/style-spec/#other-filter) and only include the ones that match. Any features in layers where no filter was specified just get passed through. And filters for the layer"*"apply to all the layers π-J filter-fileor--feature-filter-file=filter-fileβ same energy as-j, but it reads the filter out of a file π-peor--empty-csv-columns-are-nullβ treat empty CSV columns as nulls instead of as empty strings π³οΈ
βοΈ Setting or disabling tile size limits
-pkor--no-tile-size-limitβ don't skip tiles that are bigger than 500K π-pCor--no-tile-compressionβ don't compress the PBF vector tile data π€-pgor--no-tile-statsβ don't generate the tilestats row in the tileset metadata. Uploads without tilestats (https://github.com/mapbox/mapbox-geostats) will take longer to process β³--tile-stats-attributes-limit=countβ include tilestats info about at most count attributes instead of the default1000π’--tile-stats-sample-values-limit=countβ calculate tilestats attribute statistics based on count values instead of the default1000π--tile-stats-values-limit=countβ report count unique attribute values in tilestats instead of the default100π
Real talk: because tile-join literally just copies the geometries into the new.mbtileswithout processing them (except to rescale the extents if it has to), it does not have any of tippecanoe's recourses if the new tiles are bigger than the 500K tile limit. If a tile is too big and you haven't specified-pk, it's justβ¦ left out of the new tileset. Gone. Not invited π
π Example
Picture it: you've got a tileset of census blocks ποΈ
curl -L -O http://www2.census.gov/geo/tiger/TIGER2010/TABBLOCK/2010/tl_2010_06001_tabblock10.zip
unzip tl_2010_06001_tabblock10.zip
ogr2ogr -f GeoJSON tl_2010_06001_tabblock10.json tl_2010_06001_tabblock10.shp
./tippecanoe -o tl_2010_06001_tabblock10.mbtiles tl_2010_06001_tabblock10.json
β¦and a CSV of their populations π
curl -L -O http://www2.census.gov/census_2010/01-Redistricting_File--PL_94-171/California/ca2010.pl.zip
unzip -p ca2010.pl.zip cageo2010.pl |
awk 'BEGIN {
print "GEOID10,population"
}
(substr($0, 9, 3) == "750") {
print "\"" substr($0, 28, 2) substr($0, 30, 3) substr($0, 55, 6) substr($0, 62, 4) "\"," (0 + substr($0, 328, 9))
}' > population.csv
which is giving β¨thisβ¨
GEOID10,population
"060014277003018",0
"060014283014046",0
"060014284001020",0
...
"060014507501001",202
"060014507501002",119
"060014507501003",193
"060014507501004",85
...
Then you can join those populations onto the geometries and throw out the no-longer-needed ID field, like the icon you are π
./tile-join -o population.mbtiles -x GEOID10 -c population.csv tl_2010_06001_tabblock10.mbtiles
π’ tippecanoe-enumerate
The tippecanoe-enumerate utility lists the tiles that an mbtiles file defines π Each line of the output gives you the name of the mbtiles file plus the zoom, x, and y coordinates of one of the tiles. Basically it does the same thing as
select zoom_level, tile_column, (1 << zoom_level) - 1 - tile_row from tiles;
run on the file in sqlite3 ποΈ
π§ tippecanoe-decode
The tippecanoe-decode utility turns vector mbtiles back into GeoJSON π You can run it on a whole entire file:
tippecanoe-decode file.mbtiles
tippecanoe-decode file.pmtiles
or on just one single tile π―
tippecanoe-decode file.mbtiles zoom x y
tippecanoe-decode file.vector.pbf zoom x y
Unless you pass -c, the output is a set of nested FeatureCollections identifying each tile and layer separately. Just so you know: the same features generally show up at all the zooms, so the output for the file will have a bunch of copies of the same features at different resolutions. Not a bug, that's just how it is bestie π
βοΈ Options
-s projectionor--projection=projectionβ specify the projection of the output data. Currently supported:EPSG:4326(WGS84, the default) andEPSG:3857(Web Mercator) πΊοΈ-z maxzoomor--maximum-zoom=maxzoomβ specify the highest zoom level to decode from the tileset β¬οΈ-Z minzoomor--minimum-zoom=minzoomβ specify the lowest zoom level to decode from the tileset β¬οΈ-l layeror--layer=layerβ decode only the layers with the specified names. (Multiple-loptions can be specified.) π§-cor--tag-layer-and-zoomβ include each feature's layer and zoom level as part of its tippecanoe object rather than as aFeatureCollectionwrapper π·οΈ-Sor--statsβ just report statistics about each tile's size and the number of features in it, as a JSON structure π-for--forceβ decode tiles even if polygon ring order or closure problems are detected π€-Ior--integerβ report coordinates in integer tile coordinates π’-For--fractionβ report coordinates as a fraction of the tile extent β
π§ tippecanoe-json-tool π
Okay bestie, this one pulls GeoJSON features or standalone geometries out of a bigger JSON file as line-delimited JSON objects, following literally the same extraction rules Tippecanoe uses when it's parsing JSON. Same rules, same energy, no cap.
tippecanoe-json-tool file.json [... file.json]
And then, if you want, it'll:
- wrap them in a
FeatureCollectionor aGeometryCollectionas appropriate β¨ - extract an attribute out of the GeoJSON properties so you can sort by it
- join a sorted CSV of new attributes onto a sorted GeoJSON file π«Ά
Why the whole "must be sorted" thing, you ask? Because that's the only way to work on CSV and GeoJSON files that are bigger than can comfortably fit in memory β you stream through them in parallel, exactly like the Unix join command does. And to get your giant files sorted first? That's what the Unix sort command is for, queen. π
Real talk though: the sorting interface is weird, and a future version of tippecanoe-json-tool is gonna replace it with something better. So don't get attached. π
β¨ Options β¨
-w,--wrapβ adds theFeatureCollectionorGeometryCollectionwrapper for you π-eattribute,--extract=attribute β pulls out the named attribute as a prefix to each feature. Heads up: the formatting makes excessive use of\uquoting, so it follows JSON string rules but still gets sorted correctly by tools that only do plain ASCII comparisons. It's giving unhinged but it works. π-cfile.csv,--csv=file.csv β joins attributes from the named sorted CSV file, using its first column as the join key. Geometries get passed through even if they don't match the CSV, but CSV lines that don't match a geometry get discarded. Bye. π-pe,--empty-csv-columns-are-nullβ treat empty CSV columns asnulls instead of empty strings π
π Example π
Let's join Census LEHD (Longitudinal Employer-Household Dynamics) employment data β link's at https://lehd.ces.census.gov/ β onto a file of Census block geography for Tippecanoe County, Indiana. Yes, the county is real, and yes, naming stuff after it is a whole vibe. πΈ
Download the Census block geometry and convert it to GeoJSON:
$ curl -L -O https://www2.census.gov/geo/tiger/TIGER2010/TABBLOCK/2010/tl_2010_18157_tabblock10.zip
$ unzip tl_2010_18157_tabblock10.zip
$ ogr2ogr -f GeoJSON tl_2010_18157_tabblock10.json tl_2010_18157_tabblock10.shp
Download the Indiana employment data and fix the name of the join key in the header:
$ curl -L -O https://lehd.ces.census.gov/data/lodes/LODES7/in/wac/in_wac_S000_JT00_2015.csv.gz
$ gzip -dc in_wac_S000_JT00_2015.csv.gz | sed '1s/w_geocode/GEOID10/' > in_wac_S000_JT00_2015.csv
Now sort the GeoJSON block geometry so it's ordered by block ID. And like, actually do it, because if you don't you will get a "GeoJSON file is out of sort" error and the whole thing just refuses. π
$ tippecanoe-json-tool -e GEOID10 tl_2010_18157_tabblock10.json | LC_ALL=C sort > tl_2010_18157_tabblock10.sort.json
And finally, join the block geometries to the employment attributes:
$ tippecanoe-json-tool -c in_wac_S000_JT00_2015.csv tl_2010_18157_tabblock10.sort.json > blocks-wac.json
Slay. You just joined two giant datasets with streaming, bestie. π
π¦ tippecanoe-overzoom π¦
Now tippecanoe-overzoom is the icon of the family. It creates a vector tile from one of its parent tiles β clipping and scaling the geometry from that parent, and excluding features that are clipped away. The whole idea: if you make very high resolution tiles (with --extra-detail) at a moderate zoom level, you can use tippecanoe-overzoom to turn those into moderate detail tiles at high zoom levels, for the benefit of renderers that can't internally overzoom high-resolution tiles without losing some of the precision. Main character problem-solving energy tbh. β¨
So if you run:
tippecanoe-overzoom -o out.mvt.gz in.mvt.gz inz/inx/iny outz/outx/outy
it reads tile inz/inx/iny of in.mvt.gz and produces tile outz/outx/outy of out.mvt.gz. π«
And if you run:
tippecanoe-overzoom -o out.mvt.gz -t outz/outx/outy in.mvt.gz inz/inx/iny in2.mvt.gz in2z/in2x/in2y in3.mvt.gz in3z/in3x/in3y
it reads tile inz/inx/iny of in.mvt.gz, tile in2z/in2x/in2y of in2.mvt.gz, and tile in3z/in3x/in3y of in3.mvt.gz, and produces tile outz/outx/outy of out.mvt.gz from them. Three tiles in, one tile out β a whole glow-up. π
β¨ Options β¨
-bbuffer β sets the tile buffer in the output tile (default5) π«Ά-ddetail β sets the detail of the output tile (default12) π§-yattribute β retain the specified attribute in the output features. Fair warning: all attributes that are not named in a-yoption get removed. So if you forget one, it's gone gone. π-jfilter β filter features using the same expression syntax as intippecanoeπ₯-mβ if a tile was created with the--retain-points-multiplieroption, thin the tile back down to its normal feature count during overzooming. The first feature from each cluster will be retained β unless-jis used to specify a filter, in which case the first matching filter from each cluster gets retained instead π--preserve-input-orderβ restores a set of filtered features to its original input order π--accumulate-attributeβ behaves as intippecanoeto sum attributes from the features of a multiplier cluster that are not included in the final output. One important thing though: the attributes from features that get filtered away with-jare not accumulated onto the output feature. No sneaky extras. π
And that's the whole manual, bestie!! π Every section, every flag, every \u-quoted weirdness β we got through all of it, and I'm so proud of you fr fr. π«Ά
This whole thing comes from the tippecanoe() manual page, so if you ever need to cite it, that's your source. Remember: sort your files, read your warnings, and go build something iconic. Periodt. π
π¦ where this page comes from
- ubuntu stonking: tippecanoe 2.79.0-1 Β· BSD-2-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms