PMTiles Layer Support¶
This notebook demonstrates how to use PMTiles with anymap-ts MapLibre backend.
PMTiles is a single-file archive format for pyramids of map tiles that enables efficient web-native map serving without requiring a separate tile server.
Features¶
- Support for both vector and raster PMTiles
- Customizable styling for vector layers
- Layer opacity and visibility controls
- Integration with layer control panel
Installation¶
Make sure you have anymap-ts installed:
pip install anymap-ts
# %pip install anymap-ts
from anymap_ts import Map
Example 1: Auto-Discovery Mode¶
The simplest way to visualize a PMTiles file -- just provide the URL. All source layers are automatically discovered from the metadata and rendered with distinct colors, similar to https://pmtiles.io/.
m = Map(
center=[11.2558, 43.7696],
zoom=14,
)
# Auto-discover all layers with distinct colors and popups on click
m.add_pmtiles_layer(
# url="https://overturemaps-tiles-us-west-2-beta.s3.amazonaws.com/2026-01-21/buildings.pmtiles",
url="https://pmtiles.io/protomaps(vector)ODbL_firenze.pmtiles",
fit_bounds=True,
popup=True,
)
m.to_html("pmtiles.html")
m
m.pmtiles_styles
Example 2: Explicit Styling¶
For more control, provide a style dict with specific source-layer, type, and paint properties.
# Create a map focused on Firenze (Florence), Italy
m2 = Map(
center=[11.2558, 43.7696], # Florence coordinates
zoom=12,
style="https://demotiles.maplibre.org/style.json",
height="500px",
)
# Add roads as lines
m2.add_pmtiles_layer(
url="https://pmtiles.io/protomaps(vector)ODbL_firenze.pmtiles",
layer_id="roads",
style={
"type": "line",
"source-layer": "roads",
"line-color": "#2c3e50",
"line-width": 2,
"line-opacity": 0.8,
},
)
# Add buildings as fills
m2.add_pmtiles_layer(
url="https://pmtiles.io/protomaps(vector)ODbL_firenze.pmtiles",
layer_id="buildings",
style={
"type": "fill",
"source-layer": "buildings",
"fill-color": "#e74c3c",
"fill-opacity": 0.6,
"fill-outline-color": "#c0392b",
},
)
# Add points of interest as circles
m2.add_pmtiles_layer(
url="https://pmtiles.io/protomaps(vector)ODbL_firenze.pmtiles",
layer_id="pois",
style={
"type": "circle",
"source-layer": "pois",
"circle-color": "#f39c12",
"circle-radius": 4,
"circle-opacity": 0.9,
"circle-stroke-color": "#e67e22",
"circle-stroke-width": 1,
},
)
m2
Example 3: Symbol Layer for Labels¶
Use the symbol layer type to render text labels and icons from PMTiles.
Symbol layers support text-field, text-size, text-color, and other
MapLibre symbol properties.
# Add symbol layer for place labels
m3 = Map(
center=[11.2558, 43.7696], # Florence coordinates
zoom=14,
style="https://demotiles.maplibre.org/style.json",
height="500px",
)
m3.add_pmtiles_layer(
url="https://pmtiles.io/protomaps(vector)ODbL_firenze.pmtiles",
layer_id="place-labels",
style={
"type": "symbol",
"source-layer": "places",
"text-field": ["get", "name"],
"text-size": 14,
"text-color": "#1a1a2e",
"text-halo-color": "#ffffff",
"text-halo-width": 2,
"text-allow-overlap": False,
},
)
m3
Example 3b: Filtering Features¶
Use the filter parameter to show only a subset of features from a source
layer. This is useful for creating multiple toggleable layers from the same
data, each filtered by a property value. Filters use
MapLibre expression syntax.
# Create separate filtered layers from the same PMTiles source.
# Each layer shows only features matching the filter, making them
# independently toggleable in the layer control.
url = "https://pmtiles.io/protomaps(vector)ODbL_firenze.pmtiles"
m3b = Map(
center=[11.2558, 43.7696],
zoom=14,
style="https://basemaps.cartocdn.com/gl/positron-gl-style/style.json",
height="500px",
)
# Show only "major_road" features from the roads layer
m3b.add_pmtiles_layer(
url=url,
layer_id="major-roads",
style={
"type": "line",
"source-layer": "roads",
"line-color": "#e74c3c",
"line-width": 3,
},
filter=["==", ["get", "pmap:kind"], "major_road"],
)
# Show only "minor_road" features from the same roads layer
m3b.add_pmtiles_layer(
url=url,
layer_id="minor-roads",
style={
"type": "line",
"source-layer": "roads",
"line-color": "#3498db",
"line-width": 1.5,
},
filter=["==", ["get", "pmap:kind"], "minor_road"],
)
m3b
Example 4: Raster PMTiles¶
PMTiles also supports raster tiles for satellite imagery, digital elevation models, etc.
# Note: This is a placeholder example as we don't have a public raster PMTiles URL
# In practice, you would use your own raster PMTiles file
m4 = Map(
center=[-120.5, 35.5],
zoom=8,
style="https://demotiles.maplibre.org/style.json",
height="500px",
)
# Example of how to add a raster PMTiles layer
# m4.add_pmtiles_layer(
# url="https://example.com/satellite.pmtiles",
# layer_id="satellite",
# source_type="raster",
# opacity=0.8
# )
print("For raster PMTiles, use source_type='raster' and adjust opacity as needed.")
print("The layer will be added as a raster layer with the specified opacity.")
m4
Layer Management¶
You can programmatically control PMTiles layers:
# Remove a layer
# m2.remove_pmtiles_layer("roads")
# Set layer visibility
# m2.set_visibility("buildings", False)
# Set layer opacity
# m2.set_opacity("buildings", 0.3)
print("Layer management methods:")
print("- remove_pmtiles_layer(layer_id)")
print("- set_visibility(layer_id, visible)")
print("- set_opacity(layer_id, opacity)")
Style Configuration¶
The style parameter accepts MapLibre style properties:
For Fill Layers¶
style = {
"type": "fill",
"source-layer": "layer_name",
"fill-color": "#3388ff",
"fill-opacity": 0.6,
"fill-outline-color": "#ffffff"
}
For Line Layers¶
style = {
"type": "line",
"source-layer": "layer_name",
"line-color": "#ff0000",
"line-width": 2,
"line-opacity": 0.8
}
For Circle Layers¶
style = {
"type": "circle",
"source-layer": "layer_name",
"circle-color": "#00ff00",
"circle-radius": 5,
"circle-opacity": 0.9
}
For Symbol Layers (Text Labels and Icons)¶
style = {
"type": "symbol",
"source-layer": "layer_name",
"text-field": ["get", "name"],
"text-size": 14,
"text-color": "#333333",
"text-halo-color": "#ffffff",
"text-halo-width": 1,
"text-allow-overlap": False
}
Filtering Features¶
Use the filter parameter to show only matching features. Filters use
MapLibre expression syntax:
# Equality filter
filter=["==", ["get", "category"], "walking"]
# Multiple conditions (all must match)
filter=["all", ["==", ["get", "type"], "road"], [">", ["get", "width"], 5]]
# Any of several values
filter=["in", ["get", "kind"], ["literal", ["major_road", "highway"]]]
# Check if a property exists
filter=["has", "name"]
You can also apply filters after layer creation using set_filter():
m.set_filter("layer-id", ["==", ["get", "category"], "walking"])
m.set_filter("layer-id", None) # Clear filter
Benefits of PMTiles¶
- Single File: No need for complex tile server infrastructure
- Efficient: HTTP range requests enable fast random access
- Scalable: Works with CDNs and cloud storage
- Portable: Easy to share and deploy
- Cost-effective: Reduces server costs and complexity