Skip to main content

trucktrack

High-performance trajectory splitting, generation, and map-matching, powered by Rust.

A Python package implementing logic similar to movingpandas trajectory splitters (ObservationGapSplitter, StopSplitter) with a Rust backend for speed. Data flows through Polars DataFrames, with the option to process entirely in Rust (parquet in, parquet out) or share DataFrames between Python and Rust zero-copy via pyo3-polars.

In addition to the Rust splitters, trucktrack ships pure-Python subpackages for trace generation, map-matching, per-edge truck speeds as Valhalla predicted traffic (congestion), querying, and visualization. What's new in each release: CHANGELOG.md.

Install

pip install trucktrack

Optional extras:

pip install trucktrack[valhalla]  # local pyvalhalla routing & map-matching
pip install trucktrack[viz]       # folium-based interactive maps

From source

# Requires Python 3.11+ and Rust stable
git clone https://github.com/twedl/trucktrack.git
cd trucktrack
python3 -m venv .venv && source .venv/bin/activate
pip install "maturin>=1.7,<2.0" polars pytest
maturin develop

Pipelines

Group by truck, then split

Raw GPS can arrive in any file layout: parquet files anywhere under one folder, with columns id (truck), time, lat, lon, speed (km/h) and heading. First gather each truck's points into one bucket, then split each bucket's trucks into trips:

from pathlib import Path
from trucktrack import bucket_by_truck, run_pipeline

bucket_by_truck(Path("data/raw"), Path("data/bucketed"))  # n_buckets=256
run_pipeline(Path("data/bucketed"), Path("data/split"))

Buckets are a stable hash of the truck id, and every later stage keeps them (bucket=K/ folders plus a _buckets.json). run_pipeline loads one bucket per worker, so set n_buckets for your data's size.

Building Valhalla tiles

Map-matching and route generation need a local Valhalla install (pip install trucktrack[valhalla]). One-time setup (downloads Ontario from Geofabrik, builds config + admins + tiles):

python -m trucktrack.valhalla.setup

Produces valhalla_tiles/valhalla.json, valhalla_tiles/admin.sqlite, and valhalla_tiles/valhalla_tiles.tar — all gitignored. find_config() discovers the json automatically. Pass --pbf path.osm.pbf to reuse an existing OSM extract. From Python, build_tiles(pbf, tile_dir) in trucktrack.valhalla.setup does the same and returns the config path.

Map-match

Map-match all trips against a local Valhalla instance:

from trucktrack.valhalla.pipeline import run_map_matching

run_map_matching(
    Path("data/split"),
    Path("data/matched"),
    # config="valhalla.json"  # omit to auto-discover in cwd
)

Bridging large gaps

Map-match cost scales poorly when a trip has a large inter-point gap — Meili searches candidate routes across the gap and can spend seconds or minutes on a single trip. Opt in to gap-splitting by passing a BridgeConfig: trips are split at gaps, each sub-segment is matched normally, and gaps are filled in with a single /route + edge_walk call to recover way IDs:

from trucktrack.valhalla import BridgeConfig, run_map_matching

run_map_matching(
    Path("data/split"),
    Path("data/matched"),
    bridges=BridgeConfig(max_dist_m=5000, time_s=240, min_dist_m=1000),
)

A gap triggers a split when the distance between consecutive points exceeds max_dist_m, or when the time exceeds time_s and the distance exceeds min_dist_m (the distance floor keeps red-light stalls from splitting). The /route bridge assumes the truck took a shortest path through the gap — true detours are invisible. Per-trip quality rows pick up n_bridges, max_detour_ratio, total_bridge_m, and any_bridge_failed so downstream can filter. On any /route failure the orchestrator falls back to a single full HMM call with breakage_distance pinned to the base value and sets any_bridge_failed=True.

Truck speeds as predicted traffic

Match with observations, then load each edge's hourly truck speeds into the tiles; time-dependent truck routes then slow down where and when the trucks did:

from trucktrack.congestion import ObservationConfig

run_map_matching(
    Path("data/split"), Path("data/matched"), observations=ObservationConfig()
)
python -m trucktrack.valhalla.traffic data/matched

Roads no truck drove take their own Valhalla speed, scaled to how fast trucks drove roads of the same class and length and shaped by their class's week (--measured-only leaves them alone).

from datetime import datetime
from trucktrack.valhalla import route

route(origin, destination, depart_at=datetime(2026, 3, 10, 8, 0))  # local time

trucktrack/examples/congestion.py runs each step and prints what it produces. It is installed with the package: copy it from the directory python -c "import trucktrack.examples as e; print(e.__path__[0])" prints, point its settings at your data, and run it. docs/congestion.md covers the method, how it measures up on synthetic data, and its caveats.

Querying

Pull individual trucks or trips from any stage. On a bucketed stage the lookup hashes the truck id and opens only its bucket; the raw input, in whatever layout, is scanned in full:

import trucktrack as tt

df = tt.scan_truck("data/bucketed", truck_id).collect()  # or data/raw
df = tt.scan_truck("data/split", truck_id).collect()
df = tt.scan_trip("data/split", trip_id).collect()
df = tt.scan_trip("data/matched", [trip_id_1, trip_id_2]).collect()
df = tt.scan_truck("data/matched/_quality", truck_id).collect()

Visualization

One-call helpers to query, plot, and serve an interactive map:

from trucktrack.visualize import inspect_truck, inspect_trip

# All trips for a truck — opens a Flask server
inspect_truck("data/split", truck_id)

# Filter to a date range
from datetime import date
inspect_truck("data/split", truck_id,
              date_range=(date(2025, 1, 1), date(2025, 3, 1)))

# Single trip or multiple trips
inspect_trip("data/split", trip_id)
inspect_trip("data/split", [trip_id_1, trip_id_2])

# Any stage: raw points or matched results
inspect_truck("data/bucketed", truck_id)
inspect_trip("data/matched", trip_id)

# Get the map object without serving (e.g. for Jupyter display)
m = inspect_trip("data/split", trip_id, serve=False)

# Forward kwargs to plot_trace
inspect_trip("data/split", trip_id, color_by="speed")

Multi-stage overlay

Compare raw GPS, trip segments, and map-matched results on one map:

from trucktrack.visualize import inspect_pipeline

# All stages for one truck
inspect_pipeline(
    truck_id,
    raw_dir="data/bucketed",
    split_dir="data/split",
    matched_dir="data/matched",
)

# Scope to specific trips (raw layer auto-filtered to matching dates)
inspect_pipeline(
    trip_id=[trip_id_1, trip_id_2],
    raw_dir="data/bucketed",
    split_dir="data/split",
)

For more control, use the lower-level plot_trace, plot_trace_layers, save_map, and serve_map functions directly from trucktrack.visualize.

Dev workflow

Task Command
Build maturin develop
Tests pytest tests/ -v
Lint Python ruff check python/ tests/
Format Python ruff format python/ tests/
Lint Rust cargo clippy --all-targets --all-features -- -D warnings
Format Rust cargo fmt --all
Type-check mypy python/trucktrack
Build wheel maturin build --release

Metadata

Release files for trucktrack 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for trucktrack 0.2.1
File Size Uploaded Provenance Actions
trucktrack-0.2.1.tar.gz 101.4 MB With provenance Details for trucktrack-0.2.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for trucktrack 0.2.1
File Interpreter ABI Platform Actions
trucktrack-0.2.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.11 abi3 Linux glibc 2.17+ x86-64 Details for trucktrack-0.2.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Total release size: 119.1 MB

Release files / trucktrack-0.2.1.tar.gz

Download URL trucktrack-0.2.1.tar.gz
Size 101.4 MB
Tags Source
SHA-256 checksum
How to use checksums
e806b87ea48c6045f99ecd6541dfba7e95558cd1c1c9375f71a2855ebc77bcf5
BLAKE2b-256 checksum
How to use checksums
41105c7784c9b6368486b5caa6efcd7deab17c30cd8228a388d917c0b625607e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release files / trucktrack-0.2.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL trucktrack-0.2.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 17.6 MB
Tags CPython 3.11 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
15f474f9c872382aa2b575eebdbeb7e03fe5a4725f86ca591d03f8f483d10cdb
BLAKE2b-256 checksum
How to use checksums
b108a2fc340bb90a5a5297e2dff9be144107c7652f0a99c88c3ca93b49b24bb3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Security for trucktrack 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for trucktrack-0.2.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page