This guide walks a GIS analyst through using ApexVelocity's outputs in QGIS (3.22 LTR or newer, including QGIS 4.x). Everything here also applies to ArcGIS Pro and other OGC-compatible tools, since the data is standard GeoPackage / GeoJSON in EPSG:4326.
- 1. Get the data
- 2. Load a GeoPackage in QGIS
- 3. The data model
- 4. Styling & switching metrics
- 5. Analysis recipes
- 6. The Processing plugin
- 7. CRS & measurement notes
- 8. Print layouts & reproducible rendering
- 9. Interop: ArcGIS / web maps
Generate the bundled sample datasets, styles and map renders:
pip install -r requirements.txt # geopandas, shapely, fiona, contextily…
python python/examples/generate_gis_assets.pyThis writes, under the repo root:
data/
stelvio.gpkg stelvio.geojson
dragon.gpkg dragon.geojson
sf_urban.gpkg sf_urban.geojson
qgis/styles/
<route>_<metric>.qml # stand-alone QGIS styles
assets/maps/
*.png # cartographic renders
To make your own from any start/end pair:
from apexvelocity import RouteRequest
from apexvelocity.gis import route_to_geopackage
route_to_geopackage(
RouteRequest(start=(46.6178, 10.5894), end=(46.5285, 10.4543)),
"stelvio.gpkg",
default_metric="lateral_g", # the style QGIS applies on open
)- Layer → Add Layer → Add Vector Layer…, browse to
data/dragon.gpkg, and add theapex_segmentslayer (and optionallyapex_segments_nodes); or - drag
data/dragon.gpkgfrom the Browser panel onto the canvas.
The line layer loads already styled as a graduated choropleth — ApexVelocity
embeds the style in the GeoPackage's layer_styles table and marks one as the
default. No manual symbology needed.
apex_segments — one LineString feature per OSM road edge:
| Field | Meaning |
|---|---|
seg_index |
Ordinal position along the route |
distance_along_m, segment_length_m |
Chainage and edge length (m) |
speed_kmh, physics_limit_speed_kmh, speed_limit_kmh |
Achieved speed, physics cornering limit, posted limit |
lateral_g, longitudinal_g, total_accel_g |
Cornering / accel / combined load (g) |
friction_usage |
Fraction of available grip used, 0–1 |
safety_margin |
1 − friction_usage, 0–1 (higher = safer) |
difficulty_score |
Composite per-segment difficulty, 0–1 |
energy_kwh_per_km, regen_potential_j |
Energy intensity and regen potential |
comfort_score, is_uncomfortable |
Ride comfort |
curvature_1pm, curve_radius_m, grade_percent, turn_type |
Geometry |
surface_type, road_type, recommended_action |
Semantics |
apex_segments_nodes — the route vertices as Point features, handy for
labeling and graduated-point maps.
The GeoPackage ships six styles (speed, friction usage, safety margin, difficulty, lateral-G, energy). To switch the active metric:
- Layer Properties → Symbology → Style (bottom) → Load Style… → From Database and pick e.g. ApexVelocity – Safety_margin; or
- load a stand-alone style: Load Style… →
qgis/styles/dragon_safety_margin.qml.
To re-class on the fly, open Symbology → Graduated, set Value to any
numeric field (e.g. friction_usage), choose a color ramp, and click
Classify. Quantile or Natural Breaks (Jenks) work well for skewed
metrics like friction usage.
Find the high-risk segments (grip nearly exhausted) — Select by Expression:
"friction_usage" > 0.85
or flag tight, fast corners:
"curve_radius_m" < 50 AND "speed_kmh" > 40
Hot-spot the dangerous corners — load apex_segments_nodes, then
Processing → Interpolation → Heatmap (Kernel Density Estimation) weighted by
friction_usage.
Per-segment energy budget — Field Calculator, new virtual field:
"energy_kwh_per_km" * ("segment_length_m" / 1000)
Join to your own assets — spatially join the segments to a points-of-interest or jurisdiction layer (Processing → Join attributes by location) to summarise average difficulty or grip usage per zone.
Aggregate to route stats — Processing → Statistics by categories grouped
by road_type over lateral_g gives mean/percentile cornering load by road class.
Annotate any line layer without leaving QGIS:
- Copy
qgis/apexvelocity_plugin/into your QGIS profile'spython/plugins/directory (find it via Settings → User Profiles → Open Active Profile Folder), or zip the folder and use Plugins → Manage and Install Plugins → Install from ZIP. - Enable ApexVelocity in the Plugin Manager.
- Open Processing Toolbox → ApexVelocity → Annotate route with physics.
- Choose your route line layer, set road condition (dry/wet), an optional posted speed limit, and vehicle mass. Run.
You get a styled, physics-annotated segment layer. For full-fidelity physics, put
the apexvelocity package on the QGIS Python path by setting an environment
variable before launching QGIS:
export APEXVELOCITY_PATH=/path/to/ApexVelocity/pythonWithout it, the algorithm uses a built-in cornering model so it still runs.
- All layers are EPSG:4326 (WGS-84). For accurate length/area measurement or buffering, reproject to a local projected CRS first (Processing → Reproject layer, e.g. UTM or a state plane / national grid).
segment_length_manddistance_along_mare computed geodesically by ApexVelocity, so they are already metric and CRS-independent.- Web-Mercator (EPSG:3857) is fine for display over XYZ basemaps but overstates true distances at high latitude — don't measure in it.
The repository includes a PyQGIS script that builds QGIS print layouts (map +
legend + scale bar + title) over a satellite/dark basemap and exports them to
assets/qgis/:
bash qgis/run_render.sh # macOS; uses the QGIS app's bundled PythonThe script (qgis/render_layouts.py) is a clean reference for headless QGIS
rendering: it initializes a QgsApplication, loads each GeoPackage (with its
embedded style), adds an XYZ basemap, composes a QgsPrintLayout, and exports
via QgsLayoutExporter. Adapt the ROUTES list to your own data.
-
ArcGIS Pro: GeoPackage and GeoJSON load natively. Export the QGIS style to SLD (Symbology → Style → Save Style → SLD) for portable symbology.
-
Web maps (Leaflet / MapLibre / deck.gl): use the
.geojsondirectly; the numeric attributes drive client-side choropleths. -
Databases:
ogr2ogrthe GeoPackage straight into PostGIS:ogr2ogr -f PostgreSQL "PG:dbname=gis" data/dragon.gpkg apex_segments