R wrapper for the pmtiles command-line tool
PMTiles is a single-file archive format for tiled map data. This package provides R functions to work with PMTiles archives, including creating, inspecting, converting, and serving them for visualization.
Install from R-Universe:
install.packages('pmtiles', repos = c('https://walkerke.r-universe.dev', 'https://cloud.r-project.org'))
Or, install from GitHub:
# Using pak (recommended)
pak::pak("walkerke/pmtiles")
# Or using remotes
remotes::install_github("walkerke/pmtiles")
The package includes pre-compiled PMTiles binaries for:
No additional dependencies required!
library(pmtiles)
# Show basic info
pm_show("path/to/file.pmtiles")
# Get metadata as JSON
metadata <- pm_show("path/to/file.pmtiles", metadata = TRUE)
# Get TileJSON
tilejson <- pm_show("path/to/file.pmtiles", tilejson = TRUE)
The fastest way to visualize PMTiles (requires the mapgl package):
# Visualize local file
pm_view("path/to/file.pmtiles")
# Visualize remote file
pm_view("https://example.com/tiles.pmtiles")
# Customize the map
pm_view(
"path/to/file.pmtiles",
layer_type = "fill",
fill_color = "#088",
fill_opacity = 0.7,
inspect_features = TRUE # Enable hover tooltips
)
pm_view() automatically:
pm_serve() - Serves raw .pmtiles files for PMTiles.js clients
pm_serve("file.pmtiles", port = 8080)
# Simple usage with mapgl's PMTiles protocol
library(mapgl)
mapboxgl() |>
add_pmtiles_source(
id = "tiles",
url = "http://localhost:8080/file.pmtiles"
) |>
add_fill_layer(
id = "layer",
source = "tiles",
source_layer = "layer_name"
)
# Or use with pm_view() for quick visualization
pm_view("http://localhost:8080/file.pmtiles")
# Stop the server when done
pm_stop_server(port = 8080)
pm_serve_zxy() - Serves Z/X/Y tile endpoints
pm_serve_zxy("~/pmtiles/directory")
# Use with standard tile URLs
mapboxgl() |>
add_vector_source(
id = "tiles",
tiles = "http://localhost:8080/file/{z}/{x}/{y}.mvt"
) |>
add_fill_layer(
id = "layer",
source = "tiles",
source_layer = "layer_name"
)
# Serve from cloud storage without downloading
pm_serve_zxy(
bucket = r2_bucket("my-bucket", account_id = "your-cloudflare-account-id"),
public_url = "http://localhost:8080"
)
# Run in background
server <- pm_serve_zxy(background = TRUE)
pm_stop_server(server)
Use pm_serve():
pm_view()
Use pm_serve_zxy():
For very large files locally: Both approaches may have limitations. Consider:
pm_serve_zxy() which handles large files more reliablyhttp-server -p 8080 --cors with pm_view()
# Example with Node's http-server
pm_view("http://localhost:8080/YOUR_TILES.pmtiles", inspect_features = TRUE)
pm_show() - Display archive information and metadatapm_verify() - Verify archive integritypm_tile() - Extract a single tilepm_create() - Create PMTiles from GeoJSON/sf with tippecanoepm_convert() - Convert MBTiles to/from PMTilespm_extract() - Extract a region or zoom levelspm_merge() - Merge disjoint archives into onepm_cluster() - Cluster tiles for cloud uploadpm_upload() - Upload to S3/R2/GCS/Azurer2_bucket(), s3_bucket(), gcs_bucket(), azure_bucket(),
s3_compatible_bucket() - Bucket helpers for cloud storage configurationpm_edit() - Modify archive metadatapm_serve() - Start local HTTP server with CORS (serves raw .pmtiles files)pm_serve_zxy() - Serve Z/X/Y tile endpoints (works with any map client)pm_view() - Quick interactive visualizationpm_stop_server() - Stop any running PMTiles server (by port or server object)pm_version() - Show PMTiles CLI versionpm_convert(
input = "data.mbtiles",
output = "data.pmtiles"
)
pm_extract(
input = "world.pmtiles",
output = "usa.pmtiles",
bbox = c(-125, 24, -66, 49), # [west, south, east, north]
maxzoom = 10
)
pm_edit(
input = "file.pmtiles",
attribution = "© OpenStreetMap contributors",
description = "Street map of Austin, TX"
)
Bucket helpers build the destination URL for each provider, so you never
hand-assemble an s3://...?endpoint=... string. Credentials passed to a
helper go only to the pmtiles subprocess — they are never written to your R
session's environment.
# Cloudflare R2 (recommended host: no egress fees)
# Account ID: R2 dashboard > Account Details panel
# Keys: R2 dashboard > Manage R2 API Tokens
pm_upload(
input = "data.pmtiles",
remote = "data.pmtiles",
bucket = r2_bucket(
"my-tiles",
account_id = "your-cloudflare-account-id",
access_key = Sys.getenv("R2_ACCESS_KEY_ID"),
secret_key = Sys.getenv("R2_SECRET_ACCESS_KEY")
)
)
# Amazon S3 (uses your standard AWS credential chain)
pm_upload(
"data.pmtiles", "data.pmtiles",
bucket = s3_bucket("my-tiles", region = "us-east-1")
)
# Google Cloud Storage (Application Default Credentials)
pm_upload(
"data.pmtiles", "data.pmtiles",
bucket = gcs_bucket("my-tiles")
)
# Azure Blob Storage
pm_upload(
"data.pmtiles", "data.pmtiles",
bucket = azure_bucket(
"tiles-container",
storage_account = "myaccount",
access_key = Sys.getenv("AZURE_STORAGE_KEY")
)
)
# Any other S3-compatible service (MinIO, DigitalOcean Spaces, Backblaze B2, ...)
# The region is inferred from recognized endpoints (here: nyc3); for other
# services, pass region = explicitly
pm_upload(
"data.pmtiles", "data.pmtiles",
bucket = s3_compatible_bucket(
"my-tiles",
endpoint = "https://nyc3.digitaloceanspaces.com"
)
)
The same helpers work everywhere a bucket is accepted: pm_show(),
pm_extract(), pm_tile(), and pm_serve_zxy(). See ?r2_bucket for
provider-by-provider setup instructions.
Many functions support remote URLs:
# Inspect remote archive
pm_show("https://example.com/tiles.pmtiles", metadata = TRUE)
# Extract from remote source
pm_extract(
input = "https://example.com/world.pmtiles",
output = "local-region.pmtiles",
bbox = c(-98, 30, -97, 31)
)
# Visualize remote tiles
pm_view("https://example.com/tiles.pmtiles")
The pm_create() function provides a comprehensive R wrapper for tippecanoe, allowing you to create PMTiles directly from sf objects or GeoJSON files.
Note: You must install tippecanoe separately:
brew install tippecanoe
git clone https://github.com/felt/tippecanoe.git
cd tippecanoe
make -j
make install
Unfortunately, this workflow is not supported for Windows users.
library(sf)
library(pmtiles)
# Simple: Create from sf object
my_data <- st_read("data.geojson")
pm_create(my_data, "output.pmtiles", max_zoom = 14)
# Advanced: High-quality parcel tiles
pm_create(
"parcels.geojson",
"parcels.pmtiles",
layer_name = "parcels",
min_zoom = 10,
max_zoom = 18,
full_detail = 15,
preserve_input_order = TRUE,
no_tiny_polygon_reduction = TRUE,
coalesce_densest_as_needed = TRUE,
coalesce_fraction_as_needed = TRUE,
simplification = 1,
detect_shared_borders = TRUE,
other_options = c("-pf", "-pk", "-ai")
)
# Point clustering for markers
pm_create(
points_sf,
"clustered_points.pmtiles",
max_zoom = 14,
cluster_distance = 10,
cluster_maxzoom = "g",
generate_ids = TRUE
)
# With attribute filtering
pm_create(
roads_sf,
"roads.pmtiles",
include = c("name", "highway", "surface"),
drop_densest_as_needed = TRUE,
simplification = 10
)
pm_convert() to convert from MBTilespm_view() and pm_serve(): mapgl packageinst/COPYRIGHTS)This package wraps the go-pmtiles command-line tool by Protomaps.