Reproducible geospatial analysis framework with provenance tracking and CRS safety
Project description
ProvFlow
A reproducibility framework for geospatial analysis. Prevents common GIS errors and tracks everything you do automatically.
Note: This package provides a safety wrapper around GeoPandas with automatic provenance tracking. Unrelated to other "geoflow" packages on PyPI.
The Problem
GeoPandas is powerful but easy to mess up:
- Buffer in WGS84? 110,000x error (degrees vs meters)
- CRS mismatch in spatial join? Silent failures
- Invalid geometries? Crashes or wrong results
- Reproducibility? Good luck explaining what you did 6 months later
The Solution
ProvFlow wraps GeoPandas operations with automatic safety checks and provenance tracking.
from provflow import load, save, buffer, spatial_join, geo_pipeline
@geo_pipeline(name="my_analysis", track_provenance=True)
def analyze_flood_risk(parcels_path, zones_path):
parcels = load(parcels_path, validate=True, auto_fix=True)
zones = load(zones_path)
# Automatic CRS alignment, no silent errors
at_risk = spatial_join(parcels, zones, target_crs='EPSG:32610')
return at_risk
result = analyze_flood_risk.run("parcels.gpkg", "zones.gpkg")
save(result.result, "output.gpkg", provenance=result.provenance.to_dict())
What you get:
- CRS mismatches caught before they cause errors
- Invalid geometries detected and fixed
- Complete provenance metadata embedded in output file
- Publication-ready documentation of what you did
Installation
pip install provflow
Or from source:
git clone https://github.com/SenthilArun8/pyGeoflow.git
cd pyGeoflow
pip install -e .
Quick Examples
CRS Safety
from provflow import spatial_join
# This FAILS with helpful error:
result = spatial_join(gdf_wgs84, gdf_utm)
# ValueError: CRS mismatch. You must specify target_crs.
# This works:
result = spatial_join(gdf_wgs84, gdf_utm, target_crs='EPSG:32610')
Geographic CRS Warnings
from provflow import buffer
buffered = buffer(gdf_wgs84, distance=0.01)
# ⚠️ WARNING: Buffering in geographic CRS (EPSG:4326).
# Results will be in degrees, not meters!
# Consider reprojecting to a projected CRS first.
Geometry Validation
from provflow import load, validate_geometry
gdf = load("messy_data.shp", validate=True, auto_fix=True)
# Found 12 invalid geometries
# Fixing 12 invalid geometries using 'make_valid' method...
# Successfully fixed all 12 invalid geometries
Provenance Tracking
from provflow import geo_pipeline, spatial_task, load, buffer
@geo_pipeline(name="buffer_analysis", track_provenance=True)
def analyze(roads_path):
roads = load(roads_path).to_crs('EPSG:32610')
return buffer(roads, distance=100)
result = analyze.run("roads.gpkg")
result.save_provenance("analysis.json")
# Saves: operations, timing, environment, data signatures
Core Functions
I/O:
load(filepath, validate=False, auto_fix=False)- Load GeoJSON/Shapefile/GeoPackage with validationsave(gdf, filepath, provenance=None)- Save with embedded provenance metadata
Spatial Operations (CRS-safe):
spatial_join(left, right, target_crs=None)- Join with automatic CRS alignmentbuffer(gdf, distance)- Buffer with geographic CRS warningsoverlay(gdf1, gdf2, how='intersection', target_crs=None)- Overlay operationsclip(gdf, mask, target_crs=None)- Clip to boundary
Validation:
validate_geometry(gdf, auto_fix=False)- Find and fix invalid geometries
Decorators:
@geo_pipeline(name, track_provenance=True)- Track complete workflow@spatial_task(name, validate_crs=True)- Add validation to functions
Real Data Test Results
Tested on messy real-world data with self-intersections, bow-ties, CRS mismatches:
- ✅ Fixed 100% of invalid geometries (6/6)
- ✅ Prevented CRS mismatch errors
- ✅ Detected 97.7x buffering error (geographic vs projected)
- ✅ Full provenance tracking
See REAL_DATA_TEST_RESULTS.md for details.
Examples
Check out examples/ for working code:
simple_example.py- Basic operationspipeline_example.py- Complete workflow with provenancecase_study_real_errors.py- Real-world error handlingreproducible_pipeline_complete.py- Full closed-loop example
Testing
pytest tests/ -v # Run all tests
pytest tests/ --cov=provflow # With coverage (tests use 'geoflow' internally)
pytest tests/benchmarks/ # Performance tests
Status: 75 tests passing, 91.36% coverage
How It Works
ProvFlow is a thin safety wrapper around GeoPandas:
- CRS Manager - Forces explicit target_crs on mismatches
- Geometry Validator - Uses Shapely's make_valid to fix invalid geometries
- Provenance Tracker - Logs operations with timestamps and metadata
- Pipeline Decorator - Orchestrates tasks and captures execution history
No magic, just sensible defaults and forced explicitness where it matters.
Why I Built This
Got tired of:
- Debugging spatial joins that silently reprojected to the first CRS
- Buffering in WGS84 and getting wildly wrong results
- Trying to remember what operations I ran for a paper 6 months ago
- Invalid geometries causing cryptic crashes
Built ProvFlow to solve these problems for my own research. Open sourced in case it helps others.
Contributing
Found a bug or want to add a feature? Open an issue or PR. This is a solo project so response times may vary.
License
MIT License - see LICENSE file.
Citation
If you use ProvFlow in research:
@software{provflow2025,
title = {ProvFlow: Reproducible Geospatial Pipeline Framework with Provenance Tracking},
author = {Senthil Kirthieswar},
year = {2025},
url = {https://github.com/SenthilArun8/pyGeoflow}
}
Note: This is research software. It works for my use cases and passes tests, but your mileage may vary. If something breaks, open an issue with a reproducible example.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file provflow-0.1.0.tar.gz.
File metadata
- Download URL: provflow-0.1.0.tar.gz
- Upload date:
- Size: 20.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
188dc3e3255b9be1a391b69e849c380ecdbd8a9f224bc1a06e0b19b83e25a3c0
|
|
| MD5 |
bb5c1648e153af45e5f74b5f5a643d9a
|
|
| BLAKE2b-256 |
84199b9b7e3495849108635e1463b45fc37338b6baf2016f0d823d167ac9d067
|
File details
Details for the file provflow-0.1.0-py3-none-any.whl.
File metadata
- Download URL: provflow-0.1.0-py3-none-any.whl
- Upload date:
- Size: 20.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cb726ba30fa592ee8f77dff5704cc89af1f7ec83cf4d5d1e3f0bcb8c70629014
|
|
| MD5 |
5af92622795110df448eedbe8b1e8865
|
|
| BLAKE2b-256 |
f7812066b79b64134bc9f81f585cd8a738fe6ff2950869da05bca6f18f4086dc
|