Skip to main content

Roads - ranking and simplifying linestrings

This is a complex example that uses road data from Natural Earth Data. The recipe generates a ranked quality attribute for each feature based on the road type defined in the source data. Then, it filters features by these newly created quality attributes to include specific features per zoom level. 0 indicates ranking of the most importance, 6 indicates the least importance. As you zoom in, the filter checks to see if each feature's quality attribute are less than or equal to the zoom level. If that check is true, the feature appears at the designated zoom. For example, at zoom level 2, only Ferry Route, Major Highway, and Secondary Highway features will appear.

The expression provided here gives a low simplification number, 1, at the maximum zoom level, 5, but higher simplification, 10, at earlier zoom levels. Since the maxzoom in the recipe is 5, it is the highest zoom where tiles will be generated. The simplification value used at the maxzoom should be low so the features are not simplified, maintaining fidelity to the original geometry. This provides the most possible accuracy when overzooming data at zoom levels after the maxzoom, which is done once the tileset is used in a style.

{
"version": 1,
"layers": {
"roads": {
"source": "mapbox://tileset-source/{username}/road-data",
"minzoom": 0,
"maxzoom": 5,
"features": {
"attributes": {
"set": {
"quality": [
"match",
[ "get", "type" ],
"Ferry Route", 0,
"Major Highway", 1,
"Secondary Highway", 2,
"Bypass", 3,
"Beltway", 4,
"Road", 5,
"Track", 5,
6
]
}
},
"filter": [ "<=", [ "get", "quality" ], [ "zoom" ] ],
"simplification": [ "match", [ "zoom" ], 5, 1, 10 ]
}
}
}
}

The tileset on the left was generated without using any recipe options. The source data contains too much information to be viewed at a world view; features are randomly dropped to meet the 1250 Kilobyte tile size limit. You see fragmented roads because there is no logic in the recipe to dictate prioritization of features at a global and country-level perspective.

The map on the right is a tileset generated with the sample recipe above; it loads at zoom 1, only displaying features that are Ferry Routes or Major Highways. As you zoom in, additional road types appear and you see more dense networks of roads. If you zoom out to zoom 0, you will only see Ferry Routes.

Using the Tilesets CLI to generate a tileset

This section describes how to use the Tilesets CLI to generate a tileset.

  1. Download the data you'll use to create the tileset:
arrow-downDownload line-delimited GeoJSON
  1. Create a tileset source named road-data with the data you downloaded
tilesets upload-source username road-data ~/your/local/path/natural-earth-roads.ldgeojson
  1. Create your recipe as a local JSON file (for example) roads-recipe.json) with your road-data tileset source.
{
"version": 1,
"layers": {
"roads": {
"source": "mapbox://tileset-source/{username}/road-data",
"minzoom": 0,
"maxzoom": 5,
"features": {
"attributes": {
"set": {
"quality": [
"match",
[ "get", "type" ],
"Ferry Route", 0,
"Major Highway", 1,
"Secondary Highway", 2,
"Bypass", 3,
"Beltway", 4,
"Road", 5,
"Track", 5,
6
]
}
},
"filter": [ "<=", [ "get", "quality" ], [ "zoom" ] ],
"simplification": [ "match", [ "zoom" ], 5, 1, 10 ]
}
}
}
}
  1. Create a tileset with the id username.roads-rank using your recipe and name it "roads ranked and simplified". This will be an empty tileset to start, until you publish it.
tilesets create username.roads-rank --recipe ~/your/local/path/roads-recipe.json --name "roads ranked and simplified"
  1. Now you're ready to publish your tileset and start processing your data
tilesets publish username.roads-rank

Preview your tileset

  1. You can now add your new tileset to a map style to visualize its data. Below is an example of how to add the username.roads-rank tileset as a vector tile source to a Mapbox GL JS map style.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Roads - ranking and simplifying linestrings</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v3.5.1/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v3.5.1/mapbox-gl.js"></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>
// TO MAKE THE MAP APPEAR YOU MUST
// ADD YOUR ACCESS TOKEN FROM
// https://account.mapbox.com
mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v10',
zoom: 1,
center: [-71.4935, 41.5852]
});

map.on('load', () => {
map.addSource('rank-roads', {
type: 'vector',
url: 'mapbox://examples.roads-rank'
});
map.addLayer({
'id': 'rank-roads-id',
'type': 'line',
'source': 'rank-roads',
'source-layer': 'roads',
'layout': {
'line-join': 'round',
'line-cap': 'round'
},
'paint': {
'line-color': '#ff69b4',
'line-width': 1
}
});
});
</script>

</body>
</html>

Recipe options used

FieldDescriptionData type
** source**The source data to use for this layer. Tileset sources are created with the Create a tileset source endpoint of Mapbox Tiling Service (MTS).String
minzoomSpecify the minimum zoom at which the data in your tileset will be available. A value of 0 here ensures that the roads will be visible at a global level.Integer
maxzoomSpecify the maximum zoom at which the data your tileset will be tiled. Your map can be viewed past this zoom level because of overzooming, but the data at zoom levels greater than the maxzoom will be less precise. A value of 5 here ensures that the roads will be visible as the user zooms in slightly, but will not be generated in higher precision if they zoom in significantly.Integer
features.attributes.setA JSON object that maps the names of attributes to be generated to filter expressions and returns the new attribute values for the final tileset. Here it is being used to generate a new quality attribute based on the type field included in the original data.Object
features.filterA verbose filter definition. Its use here excludes any feature from tiles where their quality attribute is greater than the current zoom level. For example, features with a quality attribute of "Bypass" will not be visible at zoom levels lower than or equal to 3.Array<Expression>
features.simplificationSpecify an integer value or expression that is greater than zero to control the level of simplification that occurs for features. The expression provided here gives a high precision (1) at the maximum zoom level (5) but lower precision (10) at other zoom levels.Integer expression
Was this example helpful?