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)
| 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)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| 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 logRelease 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 logSecurity 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.
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 logA 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.