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.")
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
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
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
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']}"
)
# 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
# Show landuse areas again
m3.set_visibility("landuse_areas", True)
print("Landuse areas are now visible again")
m3
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
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
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!