NYC points of interest - reducing feature density
Points of Interest (POIs) must be visible and not overcrowded to allow users to quickly distinguish each point. They are likely going to be labels on a map or points or circles with labels. Below is a recipe suitable to visualize POI data at low to medium zooms (zoomed out).
Drop features randomly
In this recipe, we drop features to provide a visually digestible amount of POIs. Since there isn't a property that ranks features' importance (such as rating, seating capacity, etc...), we pass in a "null"
value to limit.lowest_where_in_distance
, which drops features in each tile. 256
sets the limit for the number of features in a tile - when a tile exceeds more than 256
features, features are randomly removed. This value allows space for labels of POIs if desired - the higher the threshold, the greater the density of points in your dataset.
{
"version": 1,
"layers": {
"nyc_points_layer": {
"source": "mapbox://tileset-source/{username}/nyc-pois",
"minzoom": 0,
"maxzoom": 10,
"tiles": {
"limit": [
[ "lowest_where_in_distance", true, 256, "null" ]
]
}
}
}
}
The tileset on the left was created with a recipe that doesn't drop any features and the tileset on the right was created with the recipe used above in the "Drop features randomly" section. As you can see, the tileset on the right is less dense as a result of dropping features.
Using the Tilesets CLI to generate a tileset
This section describes how to use the Tilesets CLI to generate a tileset.
- Download the data you'll use to create the tileset:
- Create a tileset source named
nyc-pois
with the data you downloaded
tilesets upload-source username nyc-pois ~/your/local/path/nyc_pois.ldgeojson
- Create your recipe as a local JSON file (for example
nyc-pois-recipe.json
) with yournyc-pois
tileset source
{
"version": 1,
"layers": {
"nyc_points_layer": {
"source": "mapbox://tileset-source/{username}/nyc-pois",
"minzoom": 0,
"maxzoom": 10,
"tiles": {
"limit": [
[ "lowest_where_in_distance", true, 256, "null" ]
]
}
}
}
}
- Create a tileset with the id
username.nyc-pois-filter
using your recipe and name it"nyc pois"
This will be an empty tileset to start, until you publish it.
tilesets create username.nyc-pois-filter --recipe ~/your/local/path/nyc-pois-recipe.json --name "nyc pois"
- Now you're ready to publish your tileset and start processing your data
tilesets publish username.nyc-pois-filter
Preview your tileset
- 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.nyc-pois-filter
tileset as a vector tile source to a Mapbox GL JS map style.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>NYC points of interest - reducing feature density</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: 10,
center: [-73.926378, 40.82048]
});
map.on('load', () => {
map.addSource('nyc-pois-src', {
type: 'vector',
url: 'mapbox://examples.nyc-pois-filter'
});
map.addLayer({
'id': 'nyc-pois-id',
'type': 'circle',
'source': 'nyc-pois-src',
'source-layer': 'nyc_points_layer',
'paint': {
'circle-radius': 4,
'circle-color': '#ff69b4'
}
});
});
</script>
</body>
</html>
Recipe options used
Field | Description | Data 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 |
minzoom | Specify the minimum zoom at which the data in your tileset will be available. | Integer |
maxzoom | Specify the maximum zoom at which the tileset will be available. A value of 10 provides up to 10 meters of precision, which is enough for relative locations of features like POIs. Your map will still zoom past the max zoom in your recipe because of overzooming | Integer |
tiles.limit.lowest_where_in_distance | This property is used to keep the number of points in each tile to a minimum, reducing the density of point data. 256 features per tile ensures space for labels. This value must be a power of 4 to match the tile grid. The accepted values are: 4, 16, 64, 256, 1024, 4096, or 16384 . | Array<Expression> |