Skip to content

API Reference

CLI

gpq-tiles [OPTIONS] <INPUT> <OUTPUT>

Arguments

Argument Description
INPUT Input GeoParquet file path
OUTPUT Output PMTiles file path

Options

Flag Default Description
--min-zoom <N> 0 Minimum zoom level
--max-zoom <N> 14 Maximum zoom level
--drop-density <LEVEL> medium Feature dropping: low, medium, high
--layer-name <NAME> (from filename) MVT layer name
--compression <ALG> gzip Compression: gzip, zstd, brotli, none
--streaming-mode <MODE> fast Streaming: fast, low-memory
-y, --include <FIELD> (all) Include property (repeatable)
-x, --exclude <FIELD> (none) Exclude property (repeatable)
-X, --exclude-all false Exclude all properties (geometry only)
--no-parallel false Disable parallel tile processing
--no-parallel-geoms false Disable parallel geometry processing
-v, --verbose false Show progress bars
--quiet false Suppress optimization warnings

Examples

# Basic
gpq-tiles input.parquet output.pmtiles

# Full options
gpq-tiles input.parquet output.pmtiles \
  --min-zoom 0 \
  --max-zoom 14 \
  --compression zstd \
  --include name \
  --include population \
  --verbose

Python API

convert()

from gpq_tiles import convert

convert(
    input: str,
    output: str,
    min_zoom: int = 0,
    max_zoom: int = 14,
    drop_density: str = "medium",
    compression: str = "gzip",
    include: list[str] | None = None,
    exclude: list[str] | None = None,
    exclude_all: bool = False,
    layer_name: str | None = None,
    streaming_mode: str = "fast",
    parallel_tiles: bool = True,
    parallel_geoms: bool = True,
    progress_callback: Callable[[dict], None] | None = None,
) -> None

Parameters:

Parameter Type Default Description
input str (required) Input GeoParquet file path
output str (required) Output PMTiles file path
min_zoom int 0 Minimum zoom level (0-22)
max_zoom int 14 Maximum zoom level (0-22)
drop_density str "medium" Feature dropping: "low", "medium", "high"
compression str "gzip" Compression: "gzip", "brotli", "zstd", "none"
include list[str] None Whitelist of property names to include
exclude list[str] None Blacklist of property names to exclude
exclude_all bool False Exclude all properties (geometry only)
layer_name str None Override layer name (default: input filename)
streaming_mode str "fast" Memory mode: "fast" or "low-memory"
parallel_tiles bool True Enable parallel tile generation
parallel_geoms bool True Enable parallel geometry processing
progress_callback Callable None Callback for progress events

Raises:

  • TypeErrorprogress_callback is not callable
  • ValueError — Invalid parameter value or conflicting filter options
  • RuntimeError — Conversion failed (file not found, invalid GeoParquet, etc.)

Examples:

from gpq_tiles import convert

# Basic conversion
convert("buildings.parquet", "buildings.pmtiles")

# With options
convert(
    input="buildings.parquet",
    output="buildings.pmtiles",
    min_zoom=0,
    max_zoom=14,
    compression="zstd",
    drop_density="high"
)

# Property filtering
convert("data.parquet", "out.pmtiles", include=["name", "population"])
convert("data.parquet", "out.pmtiles", exclude=["internal_id"])
convert("data.parquet", "out.pmtiles", exclude_all=True)  # geometry only

# Large file handling
convert("huge.parquet", "out.pmtiles", streaming_mode="low-memory")

# Progress callback
def on_progress(event):
    if event["phase"] == "complete":
        print(f"Generated {event['total_tiles']} tiles in {event['duration_secs']:.1f}s")
    elif event["phase"] == "phase1_progress":
        print(f"Reading row group {event['row_group']}/{event['total_row_groups']}")

convert("data.parquet", "out.pmtiles", progress_callback=on_progress)

Progress Events:

When using progress_callback, the callback receives a dict with a "phase" key:

Phase Description Additional Keys
"start" Phase started phase_num, name
"phase1_progress" Reading row groups row_group, total_row_groups, features_in_group, records_written
"phase1_complete" Reading complete total_records, peak_memory_bytes
"phase2_start" Sorting started
"phase2_complete" Sorting complete
"phase3_progress" Encoding tiles tiles_written, records_processed, total_records
"complete" All done total_tiles, peak_memory_bytes, duration_secs

Rust API

High-Level API

The Converter provides a simple, opinionated interface:

use gpq_tiles_core::{Converter, Config, Compression, PropertyFilter};

let config = Config {
    min_zoom: 0,
    max_zoom: 14,
    compression: Compression::Gzip,  // Default, maximum PMTiles viewer compatibility
    property_filter: PropertyFilter::Include(vec!["name".into(), "population".into()]),
    ..Default::default()
};

let converter = Converter::new(config);
converter.convert("input.parquet", "output.pmtiles")?;

Config

pub struct Config {
    pub min_zoom: u8,
    pub max_zoom: u8,
    pub extent: u32,
    pub drop_density: DropDensity,
    pub layer_name: Option<String>,
    pub property_filter: PropertyFilter,
    pub compression: Compression,
}
Field Default Description
min_zoom 0 Minimum zoom level
max_zoom 14 Maximum zoom level
extent 4096 Tile extent (MVT spec)
drop_density Medium Feature dropping level
layer_name None MVT layer name (derived from filename if None)
property_filter None Property filtering strategy
compression Gzip Compression algorithm

PropertyFilter

pub enum PropertyFilter {
    None,                         // Include all properties
    Include(Vec<String>),        // Whitelist
    Exclude(Vec<String>),        // Blacklist
    ExcludeAll,                  // Geometry only
}

Compression

pub enum Compression {
    None = 1,
    Gzip = 2,
    Brotli = 3,
    Zstd = 4,
}

Low-Level API

For fine-grained control, use the pipeline directly:

use gpq_tiles_core::pipeline::{generate_tiles, TilerConfig};
use gpq_tiles_core::PropertyFilter;
use std::path::Path;

let config = TilerConfig::new(0, 14)
    .with_density_drop(true)
    .with_density_max_per_cell(3)
    .with_property_filter(PropertyFilter::Include(vec!["name".into()]))
    .with_layer_name("buildings");

let tiles = generate_tiles(Path::new("input.parquet"), &config)?;

for tile_result in tiles {
    let tile = tile_result?;
    println!("z={} x={} y={}: {} bytes, {} features",
             tile.coord.z, tile.coord.x, tile.coord.y,
             tile.data.len(), tile.feature_count);
}

TilerConfig Builder

TilerConfig::new(min_zoom: u8, max_zoom: u8)
    .with_extent(extent: u32)                           // Default: 4096
    .with_buffer_pixels(pixels: u32)                    // Default: 8
    .with_layer_name(name: &str)                        // Default: "layer"
    .with_density_drop(enabled: bool)                   // Default: true
    .with_density_cell_size(pixels: u32)                // Default: 32
    .with_density_max_per_cell(max: usize)              // Default: 1
    .with_hilbert_sorting(enabled: bool)                // Default: true
    .with_property_filter(filter: PropertyFilter)       // Default: None
    .with_parallel_tiles(enabled: bool)                 // Default: true
    .with_parallel_geoms(enabled: bool)                 // Default: true
    .with_quiet(enabled: bool)                          // Default: false
    .with_streaming_mode(mode: StreamingMode)           // Default: Fast

StreamingMode

pub enum StreamingMode {
    Fast,         // Row-group streaming (default)
    LowMemory,    // External sort
}

Streaming API

For progress reporting and writer control:

use gpq_tiles_core::pipeline::{generate_tiles_to_writer_with_progress, ProgressEvent, TilerConfig};
use gpq_tiles_core::pmtiles_writer::StreamingPmtilesWriter;
use std::sync::Arc;

let config = TilerConfig::new(0, 14);
let mut writer = StreamingPmtilesWriter::new();

let progress = Arc::new(|event: ProgressEvent| {
    match event {
        ProgressEvent::Phase1Progress { row_group, total_row_groups, .. } => {
            println!("Reading row group {}/{}", row_group, total_row_groups);
        }
        ProgressEvent::Phase3Progress { tiles_written, .. } => {
            println!("Encoded {} tiles", tiles_written);
        }
        ProgressEvent::Complete { total_tiles, duration_secs, .. } => {
            println!("Done: {} tiles in {:.1}s", total_tiles, duration_secs);
        }
        _ => {}
    }
});

generate_tiles_to_writer_with_progress(
    Path::new("input.parquet"),
    &config,
    &mut writer,
    progress
)?;

writer.write_to_file("output.pmtiles")?;

Types

TileCoord

pub struct TileCoord {
    pub x: u32,
    pub y: u32,
    pub z: u8,
}

Web Mercator tile coordinates (XYZ scheme).

TileBounds

pub struct TileBounds {
    pub lng_min: f64,
    pub lat_min: f64,
    pub lng_max: f64,
    pub lat_max: f64,
}

Geographic bounds in WGS84 (longitude/latitude degrees).

GeneratedTile

pub struct GeneratedTile {
    pub coord: TileCoord,
    pub data: Vec<u8>,           // Uncompressed MVT bytes
    pub feature_count: usize,
}

A single generated tile with its MVT-encoded data.


Error Handling

Rust

use gpq_tiles_core::Error;

match converter.convert("input.parquet", "output.pmtiles") {
    Ok(()) => println!("Success!"),
    Err(Error::GeoParquetRead(msg)) => eprintln!("Failed to read input: {}", msg),
    Err(Error::PMTilesWrite(msg)) => eprintln!("Failed to write output: {}", msg),
    Err(Error::InvalidGeometry { feature_id, reason }) => {
        eprintln!("Invalid geometry at feature {}: {}", feature_id, reason);
    }
    Err(e) => eprintln!("Error: {}", e),
}

Python

from gpq_tiles import convert

try:
    convert("input.parquet", "output.pmtiles")
except ValueError as e:
    print(f"Invalid parameter: {e}")
except RuntimeError as e:
    print(f"Conversion failed: {e}")