Skip to main content

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.

Python 3.9+ License: MIT

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 validation
  • save(gdf, filepath, provenance=None) - Save with embedded provenance metadata

Spatial Operations (CRS-safe):

  • spatial_join(left, right, target_crs=None) - Join with automatic CRS alignment
  • buffer(gdf, distance) - Buffer with geographic CRS warnings
  • overlay(gdf1, gdf2, how='intersection', target_crs=None) - Overlay operations
  • clip(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 operations
  • pipeline_example.py - Complete workflow with provenance
  • case_study_real_errors.py - Real-world error handling
  • reproducible_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:

  1. CRS Manager - Forces explicit target_crs on mismatches
  2. Geometry Validator - Uses Shapely's make_valid to fix invalid geometries
  3. Provenance Tracker - Logs operations with timestamps and metadata
  4. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

provflow-0.1.0.tar.gz (20.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

provflow-0.1.0-py3-none-any.whl (20.2 kB view details)

Uploaded Python 3

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

Hashes for provflow-0.1.0.tar.gz
Algorithm Hash digest
SHA256 188dc3e3255b9be1a391b69e849c380ecdbd8a9f224bc1a06e0b19b83e25a3c0
MD5 bb5c1648e153af45e5f74b5f5a643d9a
BLAKE2b-256 84199b9b7e3495849108635e1463b45fc37338b6baf2016f0d823d167ac9d067

See more details on using hashes here.

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

Hashes for provflow-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cb726ba30fa592ee8f77dff5704cc89af1f7ec83cf4d5d1e3f0bcb8c70629014
MD5 5af92622795110df448eedbe8b1e8865
BLAKE2b-256 f7812066b79b64134bc9f81f585cd8a738fe6ff2950869da05bca6f18f4086dc

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page