PMTiles Support in AnyMap¶
This notebook demonstrates how to use PMTiles (Protomaps Tiles) with the MapLibre implementation in AnyMap. PMTiles is a single-file archive format for tiled data that enables efficient serving of vector tiles without a tile server.
What is PMTiles?¶
PMTiles is a cloud-optimized format for storing map tiles in a single file. It allows you to:
- Serve vector tiles directly from cloud storage (S3, CDN, etc.)
- Eliminate the need for a tile server
- Reduce costs and complexity for map deployments
- Enable offline mapping applications
Learn more at protomaps.com
# Import required modules
from anymap import MapLibreMap
import json
print("AnyMap loaded successfully!")
print("PMTiles support is built into the MapLibre implementation.")
AnyMap loaded successfully! PMTiles support is built into the MapLibre implementation.
Example 1: Basic PMTiles Usage¶
Let's start with a simple example using a PMTiles file from the Protomaps demo. This contains vector data for Florence, Italy.
# Create a map centered on Florence, Italy
m = MapLibreMap(
center=[11.25, 43.77], # Florence coordinates [lng, lat]
zoom=12,
height="600px",
width="100%",
)
# Add PMTiles data - this will use default styling
pmtiles_url = "https://pmtiles.io/protomaps(vector)ODbL_firenze.pmtiles"
m.add_pmtiles(pmtiles_url)
print(f"Added PMTiles data from: {pmtiles_url}")
print("Default layers created: landuse, roads, buildings, water")
m
Added PMTiles data from: https://pmtiles.io/protomaps(vector)ODbL_firenze.pmtiles Default layers created: landuse, roads, buildings, water
Example 2: Custom Layer Styling¶
PMTiles often contain multiple data layers. You can customize how these layers are styled by providing your own layer configurations.
# Create a new map for custom styling
m2 = MapLibreMap(
center=[43.77, 11.25],
zoom=13,
height="600px",
style="positron", # Use a light base style
)
# Define custom layers with specific styling
custom_layers = [
{
"id": "florence_buildings",
"source": "florence_pmtiles_source",
"source-layer": "landuse", # Using landuse layer from the PMTiles
"type": "fill",
"paint": {"fill-color": "#8B4513", "fill-opacity": 0.6}, # Brown color
},
{
"id": "florence_roads",
"source": "florence_pmtiles_source",
"source-layer": "roads",
"type": "line",
"paint": {
"line-color": "#FF6B35", # Orange color
"line-width": ["interpolate", ["linear"], ["zoom"], 10, 1, 15, 3],
},
},
{
"id": "florence_mask",
"source": "florence_pmtiles_source",
"source-layer": "mask",
"type": "fill",
"paint": {"fill-color": "rgba(255, 255, 255, 0.1)"},
},
]
# Add PMTiles with custom styling
m2.add_pmtiles(
pmtiles_url, layer_id="florence_pmtiles", layers=custom_layers, opacity=0.8
)
print("Added PMTiles with custom layer styling")
print("Custom layers:", [layer["id"] for layer in custom_layers])
m2
Added PMTiles with custom layer styling Custom layers: ['florence_buildings', 'florence_roads', 'florence_mask']
Example 3: Multiple PMTiles Sources¶
You can add multiple PMTiles sources to the same map, each with different styling and data.
# Create a map for multiple PMTiles demonstration
m3 = MapLibreMap(center=[43.77, 11.25], zoom=11, height="600px", style="dark-matter")
# Add the first PMTiles source with roads emphasized
roads_layers = [
{
"id": "main_roads",
"source": "pmtiles_roads_source",
"source-layer": "roads",
"type": "line",
"paint": {
"line-color": "#FFD700", # Gold color
"line-width": 2,
"line-opacity": 0.8,
},
}
]
m3.add_pmtiles(pmtiles_url, layer_id="pmtiles_roads", layers=roads_layers)
# Add the same PMTiles source again with different styling for buildings
building_layers = [
{
"id": "landuse_areas",
"source": "pmtiles_buildings_source",
"source-layer": "landuse",
"type": "fill",
"paint": {"fill-color": "#32CD32", "fill-opacity": 0.4}, # Lime green
}
]
m3.add_pmtiles(pmtiles_url, layer_id="pmtiles_buildings", layers=building_layers)
print("Added multiple PMTiles layers with different styling")
print("Gold roads and green landuse areas should be visible")
m3
Added multiple PMTiles layers with different styling Gold roads and green landuse areas should be visible
Example 4: Layer Management with PMTiles¶
PMTiles layers can be managed like any other layers in AnyMap - you can adjust opacity, visibility, and remove them.
# Check current layers
print("Current layers in the map:")
for layer_id in m3.layer_dict.keys():
layer_info = m3.layer_dict[layer_id]
print(
f" - {layer_id}: visible={layer_info['visible']}, opacity={layer_info['opacity']}"
)
Current layers in the map: - Background: visible=True, opacity=1.0 - main_roads: visible=True, opacity=1.0 - landuse_areas: visible=True, opacity=1.0
# Adjust layer properties
m3.set_opacity("main_roads", 0.5)
m3.set_visibility("landuse_areas", False)
print("Modified layer properties:")
print("- Reduced road opacity to 0.5")
print("- Hidden landuse areas")
m3
Modified layer properties: - Reduced road opacity to 0.5 - Hidden landuse areas
# Show landuse areas again
m3.set_visibility("landuse_areas", True)
print("Landuse areas are now visible again")
m3
Landuse areas are now visible again
Example 5: Export PMTiles Map to HTML¶
Maps with PMTiles can be exported to standalone HTML files for sharing or deployment.
# Create a final map for HTML export
export_map = MapLibreMap(
center=[43.77, 11.25], zoom=13, height="600px", style="voyager"
)
# Add PMTiles with default styling
export_map.add_pmtiles(pmtiles_url, layer_id="florence_export")
# Export to HTML
export_map.to_html("florence_pmtiles_map.html", title="Florence PMTiles Demo")
print("Map exported to 'florence_pmtiles_map.html'")
print("The HTML file includes PMTiles support and can be opened in any browser")
export_map
Map exported to 'florence_pmtiles_map.html' The HTML file includes PMTiles support and can be opened in any browser
Example 6: Advanced PMTiles Configuration¶
For more advanced use cases, you can create complex layer configurations that take advantage of PMTiles data structure.
# Create an advanced styled map
advanced_map = MapLibreMap(
center=[43.77, 11.25], zoom=14, height="600px", style="positron"
)
# Advanced layer configuration with expressions and filters
advanced_layers = [
{
"id": "florence_roads_by_type",
"source": "florence_advanced_source",
"source-layer": "roads",
"type": "line",
"paint": {
"line-color": [
"case",
["has", "highway"],
"#FF0000", # Red for highways
"#666666", # Gray for other roads
],
"line-width": ["interpolate", ["linear"], ["zoom"], 10, 1, 16, 4],
"line-opacity": 0.8,
},
},
{
"id": "florence_landuse_styled",
"source": "florence_advanced_source",
"source-layer": "landuse",
"type": "fill",
"paint": {
"fill-color": [
"interpolate",
["linear"],
["zoom"],
10,
"rgba(139, 69, 19, 0.3)",
15,
"rgba(139, 69, 19, 0.6)",
],
"fill-outline-color": "rgba(139, 69, 19, 0.8)",
},
},
]
advanced_map.add_pmtiles(
pmtiles_url, layer_id="florence_advanced", layers=advanced_layers
)
print("Created advanced PMTiles map with:")
print("- Color-coded roads (red for highways, gray for others)")
print("- Zoom-dependent styling")
print("- Outlined landuse areas")
advanced_map
Created advanced PMTiles map with: - Color-coded roads (red for highways, gray for others) - Zoom-dependent styling - Outlined landuse areas
Summary¶
This notebook demonstrated the PMTiles functionality in AnyMap:
✅ Key Features Covered:¶
- Basic PMTiles Usage: Simple addition of PMTiles data with default styling
- Custom Layer Styling: Creating custom layer configurations for specific visual effects
- Multiple PMTiles Sources: Adding multiple PMTiles sources to the same map
- Layer Management: Controlling opacity, visibility, and other layer properties
- HTML Export: Exporting PMTiles maps to standalone HTML files
- Advanced Configuration: Using MapLibre expressions for complex styling
🔧 Method Signature:¶
map.add_pmtiles(
pmtiles_url: str, # URL to the PMTiles file
layer_id: Optional[str] = None, # Custom layer ID (auto-generated if None)
layers: Optional[List[Dict]] = None, # Custom layer configurations
opacity: Optional[float] = 1.0, # Layer opacity (0.0 - 1.0)
visible: Optional[bool] = True, # Initial visibility
before_id: Optional[str] = None # Insert before this layer
)
🌐 PMTiles Benefits:¶
- No tile server required: Serve directly from cloud storage
- Cost effective: Reduce infrastructure costs
- Fast loading: Optimized for web delivery
- Offline capable: Works without internet connectivity
- Single file format: Easy to manage and deploy
📚 Resources:¶
PMTiles integration makes it easy to serve vector map data efficiently without complex server infrastructure!