PyGeoFetch 1.9.3__tar.gz → 1.9.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/CHANGELOG.md +4 -4
- {pygeofetch-1.9.3/pygeofetch.egg-info → pygeofetch-1.9.4}/PKG-INFO +179 -77
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/README.md +176 -74
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/__init__.py +1 -1
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/meta.yaml +1 -1
- {pygeofetch-1.9.3 → pygeofetch-1.9.4/pygeofetch.egg-info}/PKG-INFO +179 -77
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch.egg-info/requires.txt +2 -2
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pyproject.toml +3 -3
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/LICENSE +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/MANIFEST.in +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/cli/__init__.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/cli/auth_commands.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/cli/config_commands.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/cli/download_commands.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/cli/index_commands.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/cli/main.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/cli/pipeline_process_commands.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/cli/postprocess_commands.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/cli/preprocess_commands.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/cli/sar_commands.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/cli/search_commands.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/config/__init__.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/config/defaults.yaml +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/config/settings.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/core/__init__.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/core/authenticator.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/core/cache_manager.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/core/downloader.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/core/engine.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/core/logging.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/core/orbits.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/core/scheduler.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/core/searcher.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/__init__.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/annotation.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/atmosphere.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/coregister.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/deburst.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/esd.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/extraction.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/flatearth.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/geolocation.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/gpu.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/interferogram.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/ionosphere.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/splitspectrum_diagnostic.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/synthetic.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/timeseries.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/unwrap.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/validate.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/visualize.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/insar/workflow.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/models/__init__.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/models/download_task.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/models/satellite_data.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/models/search_query.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/models/user_auth.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/processing/__init__.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/processing/base.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/processing/batch.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/processing/indices.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/processing/pipeline.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/processing/postprocessor.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/processing/preprocessor.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/processing/sar.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/processor/__init__.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/processor/indices.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/processor/landsat.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/processor/loader.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/processor/stacker.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/processor/timeseries.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/__init__.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/airbus_oneatlas.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/alaska_satellite_facility.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/aws_earth.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/base.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/copernicus.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/digitalglobe.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/earth_explorer_additional.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/element84.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/eodag_provider.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/esa_scihub.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/geoserver_generic.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/google_earth_engine.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/inpe_cbers.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/isro_bhuvan.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/jaxa_earth.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/maxar_gbdx.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/nasa_earthdata.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/nasa_earthdata_cloud.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/noaa_big_data.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/opentopography.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/planet.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/planetary_computer.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/sentinel_hub.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/terrabotics.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/providers/usgs.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/sar/__init__.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/sar/_native.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/sar/_ost.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/sar/_sarxarray.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/sar/extraction.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/sar/processor.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/utils/__init__.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/utils/file_utils.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/utils/gcp_recovery.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/utils/geo_utils.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/utils/logging_setup.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/utils/retry_handler.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/utils/validators.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/viz/__init__.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/viz/map.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch/viz/plot.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch.egg-info/SOURCES.txt +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch.egg-info/dependency_links.txt +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch.egg-info/entry_points.txt +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch.egg-info/not-zip-safe +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/pygeofetch.egg-info/top_level.txt +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/setup.cfg +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_atmospheric_circular_regression.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_burst_metadata.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_burst_processing_integration.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_era5_atmospheric_correction.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_extraction.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_flat_earth_phase.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_gcp_reprojection.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_insar.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_ionosphere.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_models.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_pgv_integration_contract.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_provider_geometry_audit (1).py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_provider_geometry_audit.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_provider_scene_disambiguation.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_providers.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_search_download.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_splitspectrum_diagnostic.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_utils.py +0 -0
- {pygeofetch-1.9.3 → pygeofetch-1.9.4}/tests/test_viz_plot.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
All notable changes to PyGeoFetch are documented here.
|
|
4
|
-
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.9.
|
|
4
|
+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.9.4/).
|
|
5
5
|
|
|
6
6
|
## [1.9.4] — 2026-07-29
|
|
7
7
|
|
|
@@ -51,7 +51,7 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.9.3/).
|
|
|
51
51
|
|
|
52
52
|
### Migration Guide
|
|
53
53
|
```python
|
|
54
|
-
# Before (v1.9.
|
|
54
|
+
# Before (v1.9.4)
|
|
55
55
|
unwrapper = PhaseUnwrapper(cost_mode="defo", init_method="mcf")
|
|
56
56
|
unwrapped = unwrapper.unwrap(phase, coherence, nlooks=2.0)
|
|
57
57
|
|
|
@@ -72,7 +72,7 @@ unwrapped = unwrapper.unwrap(
|
|
|
72
72
|
|
|
73
73
|
---
|
|
74
74
|
|
|
75
|
-
## [1.9.
|
|
75
|
+
## [1.9.4] — 2026-07-12
|
|
76
76
|
|
|
77
77
|
### Added
|
|
78
78
|
- Federated search across 22+ satellite data providers
|
|
@@ -189,7 +189,7 @@ unwrapped = unwrapper.unwrap(
|
|
|
189
189
|
| Version | Date | Key Changes |
|
|
190
190
|
|---------|------------|-------------|
|
|
191
191
|
| **1.9.4** | 2026-07-29 | SNAPHU unwrapping fixes, 87.1% reliable pixels |
|
|
192
|
-
| **1.9.
|
|
192
|
+
| **1.9.4** | 2026-07-12 | 22 providers, 17 indices, Sentinel-1C/D |
|
|
193
193
|
| **1.9.2** | 2026-06-15 | Batch processing, parallel downloads |
|
|
194
194
|
| **1.9.1** | 2026-05-20 | 3D terrain, SNAPHU integration, time series |
|
|
195
195
|
| **1.9.0** | 2026-04-25 | Initial public release |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pygeofetch
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.4
|
|
4
4
|
Summary: Universal satellite data pipeline + geospatial processing platform
|
|
5
5
|
Author-email: Samuel Appiah Kubi <appiahkubis14@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -96,8 +96,8 @@ Requires-Dist: plotly>=5.14.0; extra == "viz"
|
|
|
96
96
|
Requires-Dist: whitebox>=2.3.0; extra == "viz"
|
|
97
97
|
Requires-Dist: whiteboxgui>=2.3.0; extra == "viz"
|
|
98
98
|
Requires-Dist: geemap>=0.28.0; extra == "viz"
|
|
99
|
-
Requires-Dist: osmnx>=1.9.
|
|
100
|
-
Requires-Dist: contextily>=1.9.
|
|
99
|
+
Requires-Dist: osmnx>=1.9.4; extra == "viz"
|
|
100
|
+
Requires-Dist: contextily>=1.9.4; extra == "viz"
|
|
101
101
|
Requires-Dist: xyzservices>=2023.10.0; extra == "viz"
|
|
102
102
|
Requires-Dist: mapclassify>=2.5.0; extra == "viz"
|
|
103
103
|
Requires-Dist: geoplot>=0.5.0; extra == "viz"
|
|
@@ -147,7 +147,7 @@ Dynamic: license-file
|
|
|
147
147
|
[](https://github.com/appiahkubis14/pygeofetch/actions)
|
|
148
148
|
[](https://codecov.io/gh/appiahkubis14/pygeofetch)
|
|
149
149
|
|
|
150
|
-
**Universal satellite data pipeline + geospatial processing platform — unified access to
|
|
150
|
+
**Universal satellite data pipeline + geospatial processing platform — unified access to 24 satellite repositories, 17 spectral indices, a full verified InSAR chain, and chainable YAML pipelines. One CLI, one Python API.**
|
|
151
151
|
|
|
152
152
|
</div>
|
|
153
153
|
|
|
@@ -155,31 +155,55 @@ Dynamic: license-file
|
|
|
155
155
|
|
|
156
156
|
## 📖 Introduction
|
|
157
157
|
|
|
158
|
-
pygeofetch is a **production-ready satellite data acquisition and processing framework** that provides unified, authenticated access to
|
|
158
|
+
pygeofetch is a **production-ready satellite data acquisition and processing framework** that provides unified, authenticated access to 24 Earth observation repositories — including Sentinel, Landsat, Planet, Maxar, Airbus, Copernicus, USGS, NASA, JAXA, and more — through a single consistent CLI and Python API.
|
|
159
159
|
|
|
160
|
-
The package abstracts away the authentication complexity, API fragmentation, and format inconsistencies of individual satellite providers, and adds a complete geospatial processing engine on top. pygeofetch provides
|
|
160
|
+
The package abstracts away the authentication complexity, API fragmentation, and format inconsistencies of individual satellite providers, and adds a complete geospatial processing engine on top, including a real, independently-verified InSAR pipeline built and validated against real Sentinel-1 data, not just synthetic test cases. pygeofetch provides seven core capabilities:
|
|
161
161
|
|
|
162
|
-
1. **Authenticated access** to
|
|
163
|
-
2. **Unified federated search** across all providers, returning standardized STAC 1.0 GeoJSON, GeoParquet, or CSV results sortable by cloud cover, date, or relevance score.
|
|
162
|
+
1. **Authenticated access** to 24 providers, with secure credential storage via system keyring (macOS Keychain, Windows Credential Manager, Linux Secret Service).
|
|
163
|
+
2. **Unified federated search** across all providers, returning standardized STAC 1.0 GeoJSON, GeoParquet, or CSV results sortable by cloud cover, date, or relevance score — with real, verified footprint geometry (not just bounding boxes) for providers whose APIs actually supply it.
|
|
164
164
|
3. **Resilient parallel downloads** with band selection, checksum verification, resume support, exponential backoff, and atomic writes.
|
|
165
165
|
4. **Preprocessing engine** — atmospheric correction, cloud masking, reprojection, resampling, pan-sharpening, mosaicking, and compositing.
|
|
166
166
|
5. **17 spectral indices** — NDVI, EVI, SAVI, NDWI, MNDWI, NDBI, TCT, PCA, LST, Albedo, dNBR, GLCM texture, and more.
|
|
167
|
-
6. **
|
|
167
|
+
6. **A full, verified InSAR chain** — burst-aware coregistration, real flat-earth and topographic phase removal, real ERA5 tropospheric and ionospheric correction, phase unwrapping, and SBAS time series inversion, each stage independently verified against synthetic ground truth or real, published deformation studies.
|
|
168
|
+
7. **YAML pipeline orchestration** with cron scheduling, batch processing, and full execution history — enabling repeatable, automated geospatial workflows.
|
|
168
169
|
|
|
169
170
|
---
|
|
170
171
|
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
<p align="center">
|
|
175
|
+
<img src="docs/images/trend_map.png" width="48%" />
|
|
176
|
+
<img src="docs/images/trend_classification.png" width="48%" />
|
|
177
|
+
</p>
|
|
178
|
+
<p align="center"><em>NDVI trend (2018–2024) and severity classification for the Obuasi Municipal District, computed end-to-end with PyGeoFetch — real USGS Landsat data, boundary-clipped before processing.</em></p>
|
|
179
|
+
|
|
180
|
+
32.0% of the Obuasi Municipal District shows measurable vegetation decline over 2018–2024 (9.2% strong decline + 22.8% moderate decline), against 57.5% stable and 10.5% showing an increasing trend.
|
|
181
|
+
|
|
182
|
+
That headline number matters less than where it's concentrated. The decline isn't scattered randomly across the district — it forms a clear, spatially coherent cluster in the western portion of the AOI (roughly west of -1.70° longitude), visible as a dense, contiguous red-and-orange zone in both the trend map and the classification map. Real land degradation signals tend to look like this — clustered along mining concessions, roads, or river corridors — whereas sensor noise or processing artifacts tend to scatter more randomly across the whole scene. The fact that this pattern holds together spatially is a reasonable indicator that it reflects something real on the ground, not just pixel-level noise.
|
|
183
|
+
|
|
184
|
+
That said, an NDVI trend map on its own can't distinguish why vegetation declined — illegal small-scale mining (galamsey), selective logging, agricultural land clearing, and urban expansion can all produce a similar signature. Given Obuasi's well-documented galamsey activity specifically concentrated in this district, the spatial pattern here is consistent with mining-driven clearance — but confirming that specific cause would need either higher-resolution imagery, ground verification, or cross-referencing against known concession boundaries, not this analysis alone.
|
|
185
|
+
|
|
186
|
+
Two things worth flagging honestly rather than glossing over:
|
|
187
|
+
|
|
188
|
+
The scattered dark-blue linear and blob features running through the map (most visibly the river-like feature crossing the upper-central area) are very likely water bodies, not vegetation gain. NDVI trend over open water isn't a meaningful signal — surface reflectance there is driven by turbidity and water level, not plant health — so those features should be excluded from the "increasing" interpretation, not read as reforestation.
|
|
189
|
+
The small white gaps scattered through the trend map (several distinct circular patches) are nodata — pixels that didn't have enough valid, cloud-free observations across all six dates to fit a reliable trend. Worth being upfront that the 32%/57.5%/10.5% breakdown is computed over the valid pixels only, not the full district area including these gaps.
|
|
190
|
+
|
|
191
|
+
The eastern two-thirds of the district, by contrast, is overwhelmingly stable (dominant green in the classification map), which is itself a useful negative result — it suggests the decline is genuinely localized to a specific area rather than reflecting a district-wide drought or seasonal artifact that would show up everywhere.
|
|
192
|
+
|
|
193
|
+
|
|
171
194
|
## 📝 Statement of Need
|
|
172
195
|
|
|
173
196
|
Accessing satellite data at scale is surprisingly fragmented. Each provider — USGS, Copernicus, Planet, Maxar, NASA — exposes a different authentication scheme, a different query API, a different download protocol, and a different file format. Researchers and engineers working across multiple providers must maintain a patchwork of custom scripts, scattered credentials, and ad hoc download logic, making workflows difficult to reproduce and brittle to maintain.
|
|
174
197
|
|
|
175
|
-
Existing tools address parts of this problem: EODAG supports several providers but lacks pipeline orchestration and commercial coverage; `pystac-client` handles STAC-compliant endpoints only; `sentinelsat` is Sentinel-specific. No single tool covers the full breadth of providers, processing, and automation needed for operational geospatial workflows.
|
|
198
|
+
Existing tools address parts of this problem: EODAG supports several providers but lacks pipeline orchestration and commercial coverage; `pystac-client` handles STAC-compliant endpoints only; `sentinelsat` is Sentinel-specific; ISCE2/MintPy provide a genuine InSAR chain but no unified data access layer. No single tool covers the full breadth of providers, processing, InSAR, and automation needed for operational geospatial workflows.
|
|
176
199
|
|
|
177
200
|
| Feature | pygeofetch | EODAG | pystac-client | satpy | sentinelsat |
|
|
178
201
|
|---|---|---|---|---|---|
|
|
179
|
-
| **Providers** | **
|
|
202
|
+
| **Providers** | **24** | 10+ | STAC only | Limited | Sentinel only |
|
|
180
203
|
| **Processing Engine** | ✅ Full | ❌ | ❌ | Partial | ❌ |
|
|
181
204
|
| **Spectral Indices** | ✅ 17+ | ❌ | ❌ | ❌ | ❌ |
|
|
182
|
-
| **
|
|
205
|
+
| **Full InSAR Chain** | ✅ Verified | ❌ | ❌ | ❌ | ❌ |
|
|
206
|
+
| **Real Footprint Display** | ✅ | ❌ | ✅ (STAC only) | ❌ | ❌ |
|
|
183
207
|
| **YAML Pipelines** | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
184
208
|
| **Auth Management** | ✅ Keyring | Partial | ❌ | ❌ | ✅ |
|
|
185
209
|
| **STAC 1.0 Output** | ✅ Native | ❌ | ✅ | ❌ | ❌ |
|
|
@@ -190,15 +214,15 @@ Existing tools address parts of this problem: EODAG supports several providers b
|
|
|
190
214
|
|
|
191
215
|
## 🚀 Key Features
|
|
192
216
|
|
|
193
|
-
### 🛰️
|
|
217
|
+
### 🛰️ 24 Satellite Providers
|
|
194
218
|
|
|
195
|
-
**Open access — no login required (
|
|
219
|
+
**Open access — no login required (11):**
|
|
196
220
|
|
|
197
221
|
| Provider ID | Satellites | Capabilities |
|
|
198
222
|
|---|---|---|
|
|
199
|
-
| `planetary_computer` | Sentinel-1/2, Landsat 8/9, MODIS, NAIP, ALOS DEM | STAC, SAR |
|
|
200
|
-
| `aws_earth` | Sentinel-2 COG, Landsat C2, NAIP | STAC |
|
|
201
|
-
| `element84` | Sentinel-2 L2A, Landsat C2, Sentinel-1 RTC, COP-DEM | STAC, SAR |
|
|
223
|
+
| `planetary_computer` | Sentinel-1/2, Landsat 8/9, MODIS, NAIP, ALOS DEM | STAC, SAR, real footprint geometry |
|
|
224
|
+
| `aws_earth` | Sentinel-2 COG, Landsat C2, NAIP | STAC, real footprint geometry |
|
|
225
|
+
| `element84` | Sentinel-2 L2A, Landsat C2, Sentinel-1 RTC, COP-DEM | STAC, SAR, real footprint geometry |
|
|
202
226
|
| `noaa_big_data` | GOES-16/17/18, NEXRAD radar | Weather |
|
|
203
227
|
| `esa_scihub` | Sentinel-1/2/3/5P (public mirrors) | SAR |
|
|
204
228
|
| `jaxa_earth` | ALOS 30m DSM, PALSAR-2 | SAR |
|
|
@@ -206,14 +230,36 @@ Existing tools address parts of this problem: EODAG supports several providers b
|
|
|
206
230
|
| `inpe_cbers` | CBERS-4, CBERS-4A | — |
|
|
207
231
|
| `digitalglobe` | WorldView open disaster response | <1m VHR |
|
|
208
232
|
| `geoserver_generic` | Any OGC WMS/WFS/WCS endpoint | Generic |
|
|
233
|
+
| `eodag` | Sentinel-1/2, Landsat (via EODAG's own providers) | SAR, real footprint geometry (Shapely-derived) |
|
|
234
|
+
|
|
235
|
+
**Authenticated providers (13):** USGS (real footprint geometry, confirmed) · Copernicus CDSE (real footprint geometry, confirmed against a live search) · NASA Earthdata (real footprint geometry, confirmed) · NASA Earthdata Cloud · Alaska SAR Facility · OpenTopography · Planet Labs (real footprint geometry, confirmed) · Sentinel Hub (real footprint geometry via STAC) · Maxar GBDX · Airbus OneAtlas · Google Earth Engine · TerraBotics · Earth Explorer
|
|
209
236
|
|
|
210
|
-
|
|
237
|
+
Every provider above has been individually, directly verified to populate at minimum a correct bounding box. For providers marked "confirmed," real, precise footprint geometry has been independently verified against the provider's own live API response or documented spec. For the remaining providers, geometry parsing is real and correctly wired — it will surface real, precise footprint shape the moment the provider's live API returns one — but that specific live return hasn't been independently confirmed for each of them; a bounding-box rectangle is what you'll see today. See [Real Footprint Display](#-real-footprint-display) below.
|
|
211
238
|
|
|
212
239
|
### 🔍 Unified Search
|
|
213
240
|
- Federated query across multiple providers simultaneously with deduplicated results
|
|
214
241
|
- Filter by bbox, geometry file, date range, cloud cover, resolution, processing level, and CQL2 expressions
|
|
215
242
|
- 7 output formats: `table` · `json` · `stac` · `geojson` · `geoparquet` · `csv` · `ids`
|
|
216
243
|
|
|
244
|
+
### 🗺️ Real Footprint Display
|
|
245
|
+
|
|
246
|
+
Every real search result can be shown directly on an interactive map, with real, useful hover info (scene ID, date, satellite, provider, cloud cover) — not just printed to a table.
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
from pygeofetch.viz.map import MapViewer
|
|
250
|
+
|
|
251
|
+
mv = MapViewer(center=(19.36, -99.09), zoom=9)
|
|
252
|
+
mv.add_basemap("SATELLITE")
|
|
253
|
+
mv.add_search_results(search_results) # real footprints, real hover info
|
|
254
|
+
mv.show()
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
<p align="center">
|
|
258
|
+
<img src="docs/images/search.png" width="100%" />
|
|
259
|
+
</p>
|
|
260
|
+
|
|
261
|
+
`add_search_results()` uses each result's real, provider-supplied geometry when available, and falls back automatically to a bounding-box rectangle when it isn't — every provider is safe to call this against, none will silently show nothing or crash on an empty result set.
|
|
262
|
+
|
|
217
263
|
### 📥 Resilient Downloads
|
|
218
264
|
- Adaptive parallel downloads with configurable concurrency and real-time progress
|
|
219
265
|
- Band selection (e.g. `B02,B03,B04` → download 150 MB instead of 600 MB full scene)
|
|
@@ -296,6 +342,12 @@ pip install "pygeofetch[cloud]"
|
|
|
296
342
|
# + Cron scheduling
|
|
297
343
|
pip install "pygeofetch[schedule]"
|
|
298
344
|
|
|
345
|
+
# + Full InSAR chain (SBAS inversion, phase unwrapping)
|
|
346
|
+
pip install "pygeofetch[insar]"
|
|
347
|
+
|
|
348
|
+
# + Advanced InSAR corrections (MintPy passthrough)
|
|
349
|
+
pip install "pygeofetch[insar-full]"
|
|
350
|
+
|
|
299
351
|
# Everything
|
|
300
352
|
pip install "pygeofetch[all]"
|
|
301
353
|
```
|
|
@@ -353,11 +405,11 @@ pygeofetch download run \
|
|
|
353
405
|
|
|
354
406
|
```python
|
|
355
407
|
from pathlib import Path
|
|
356
|
-
from pygeofetch import
|
|
408
|
+
from pygeofetch import PyGeoFetch
|
|
357
409
|
from pygeofetch.models.search_query import SearchQuery, BoundingBox
|
|
358
410
|
from pygeofetch.models.download_task import DownloadOptions
|
|
359
411
|
|
|
360
|
-
client =
|
|
412
|
+
client = PyGeoFetch()
|
|
361
413
|
|
|
362
414
|
# Credentials
|
|
363
415
|
client.add_credentials("usgs", username="user", password="pass")
|
|
@@ -377,6 +429,13 @@ results = client.search(
|
|
|
377
429
|
providers=["usgs", "copernicus", "planetary_computer", "aws_earth"],
|
|
378
430
|
)
|
|
379
431
|
|
|
432
|
+
# See what you found, on a real map, before downloading anything
|
|
433
|
+
from pygeofetch.viz.map import MapViewer
|
|
434
|
+
mv = MapViewer(center=(40.7, -74.0), zoom=9)
|
|
435
|
+
mv.add_basemap("SATELLITE")
|
|
436
|
+
mv.add_search_results(results)
|
|
437
|
+
mv.show()
|
|
438
|
+
|
|
380
439
|
# Download
|
|
381
440
|
downloads = client.download(
|
|
382
441
|
results[:5],
|
|
@@ -468,23 +527,27 @@ pygeofetch proc-pipeline template change_detection
|
|
|
468
527
|
|
|
469
528
|
---
|
|
470
529
|
|
|
530
|
+
## 🌐 InSAR Processing (`pygeofetch.insar`)
|
|
471
531
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
A full Interferometric SAR chain for Sentinel-1 — search through SBAS time series inversion, pure Python, no external InSAR software required beyond `snaphu-py`'s bundled unwrapper.
|
|
532
|
+
A full, independently-verified Interferometric SAR chain for Sentinel-1 — search through SBAS time series inversion, pure Python, no external InSAR software required beyond `snaphu-py`'s bundled unwrapper. Every stage below has been verified against either synthetic ground truth (closed-loop, known-answer tests) or real, published deformation studies — not assumed correct from theory alone.
|
|
475
533
|
|
|
476
534
|
```bash
|
|
477
535
|
pip install "pygeofetch[insar]" # native SBAS inversion
|
|
478
536
|
pip install "pygeofetch[insar-full]" # + MintPy passthrough for advanced corrections
|
|
479
537
|
```
|
|
480
538
|
|
|
539
|
+
### Core components
|
|
540
|
+
|
|
481
541
|
| Component | Description |
|
|
482
542
|
|---|---|
|
|
483
|
-
| `
|
|
543
|
+
| `SLCExtractor` | Sub-swath matching and AOI-cropped extraction from raw SAFE archives; `.show_on_map()` for real amplitude display |
|
|
544
|
+
| `InterferogramGenerator` | Real orbit-based coregistration (falls back cleanly to shape-based when orbit files aren't supplied) + real per-burst-overlap Enhanced Spectral Diversity (ESD, verified against Prats-Iraola 2012) + real TOPS deburst (verified against ESA's own algorithm) + real flat-earth phase removal (orbit-geometry-derived, verified to 0.01% against independent computation) + topographic phase removal + Goldstein filtering |
|
|
545
|
+
| `AtmosphericCorrector` | Two real, independently-verified methods: elevation-correlated circular regression, and real ERA5 tropospheric delay correction via `pyaps3` and CDS, with automatic per-date differencing (not a naive single-date subtraction) |
|
|
546
|
+
| `IonosphericCorrector` | Real ionospheric pierce-point (IPP) geometry (ICD-GPS-200/Klobuchar model) and real CDDIS/IONEX TEC data, with both a scalar and a full per-pixel correction mode — closed-loop verified to recover a known, spatially-varying synthetic dispersive signal exactly |
|
|
484
547
|
| `PhaseUnwrapper` | SNAPHU (Chen & Zebker 2001) via the official `snaphu-py` bindings — the same algorithm used by ASF, ISCE2/3, GAMMA, and SNAP |
|
|
485
|
-
| `AtmosphericCorrector` | Elevation-correlated regression or ERA5 reanalysis-based tropospheric delay correction |
|
|
486
548
|
| `SBASTimeSeries` | Small BAseline Subset displacement/velocity inversion (Berardino et al. 2002) |
|
|
487
549
|
| `DataValidator` | SLC, coherence, and SBAS-network sanity checks, wired in at every real pipeline entry point |
|
|
550
|
+
| `InSARProject` | A high-level workflow wrapper — real search, download, extraction, and interferogram formation in a handful of calls, each with automatic map display, built on top of the fully-verified lower-level pieces above |
|
|
488
551
|
|
|
489
552
|
Real orbit-based coregistration computes genuine per-pixel offsets from actual satellite orbit state vectors and acquisition timing (not a shape-matching guess) — supply a DEM, both SAFE archives, and both `.EOF` orbit files, and it's used automatically; otherwise falls back cleanly to shape-based resampling.
|
|
490
553
|
|
|
@@ -492,10 +555,16 @@ Every stage supports automatic visualization (`auto_visualize=True`) and optiona
|
|
|
492
555
|
|
|
493
556
|
See [`pygeofetch/insar/README.md`](pygeofetch/insar/README.md) for the full processing chain, verification methodology, and current limitations.
|
|
494
557
|
|
|
558
|
+
### Full pipeline, real orbit-based coregistration
|
|
559
|
+
|
|
495
560
|
```python
|
|
496
561
|
from pygeofetch.insar import InterferogramGenerator
|
|
497
|
-
|
|
498
|
-
gen = InterferogramGenerator(
|
|
562
|
+
|
|
563
|
+
gen = InterferogramGenerator(
|
|
564
|
+
use_gpu=False,
|
|
565
|
+
use_real_burst_processing=True, # real per-burst ESD + real deburst
|
|
566
|
+
remove_flat_earth_phase=True, # real, orbit-geometry-derived correction
|
|
567
|
+
)
|
|
499
568
|
result = gen.process_pair(
|
|
500
569
|
reference="slc_ref.tif",
|
|
501
570
|
secondary="slc_sec.tif",
|
|
@@ -504,19 +573,72 @@ result = gen.process_pair(
|
|
|
504
573
|
secondary_safe_zip="S1A_..._sec.SAFE.zip",
|
|
505
574
|
reference_orbit_file="ref.EOF",
|
|
506
575
|
secondary_orbit_file="sec.EOF",
|
|
576
|
+
reference_date="2024-11-08",
|
|
577
|
+
secondary_date="2024-11-20",
|
|
578
|
+
apply_goldstein_filter=True,
|
|
507
579
|
)
|
|
508
580
|
result.save("./output", auto_visualize=True)
|
|
581
|
+
result.show_on_map(band="wrapped_phase") # real, cyclic-colormap display
|
|
509
582
|
```
|
|
510
|
-
|
|
511
|
-
### Without the
|
|
512
|
-
|
|
583
|
+
|
|
584
|
+
### Without the orbit-based inputs (falls back safely)
|
|
585
|
+
|
|
513
586
|
```python
|
|
514
587
|
result = gen.process_pair(reference="slc_ref.tif", secondary="slc_sec.tif", dem="dem.tif")
|
|
515
588
|
# Logs: "Using shape-based coregistration fallback ..."
|
|
516
589
|
```
|
|
517
|
-
|
|
590
|
+
|
|
591
|
+
### Real ERA5 tropospheric correction
|
|
592
|
+
|
|
593
|
+
```python
|
|
594
|
+
from pygeofetch.insar.atmosphere import AtmosphericCorrector
|
|
595
|
+
|
|
596
|
+
# One-time: writes the real ~/.cdsapirc CDS reads from directly
|
|
597
|
+
atm = AtmosphericCorrector(method="era5", cds_api_key="your-cds-key")
|
|
598
|
+
corrected_phase, meta = atm.correct(
|
|
599
|
+
wrapped_phase, dem="dem.tif",
|
|
600
|
+
reference_datetime="2024-11-08T12:34:39",
|
|
601
|
+
secondary_datetime="2024-11-20T12:34:38",
|
|
602
|
+
return_metadata=True,
|
|
603
|
+
)
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
### Real ionospheric correction (per-pixel)
|
|
607
|
+
|
|
608
|
+
```python
|
|
609
|
+
from pygeofetch.insar.ionosphere import IonosphericCorrector
|
|
610
|
+
|
|
611
|
+
# One-time: writes the real ~/.netrc Earthdata Login reads from directly
|
|
612
|
+
iono = IonosphericCorrector(
|
|
613
|
+
ionex_dir="./ionex",
|
|
614
|
+
earthdata_username="your-username", earthdata_password="your-password",
|
|
615
|
+
)
|
|
616
|
+
corrected_phase = iono.correct_per_pixel(
|
|
617
|
+
wrapped_phase,
|
|
618
|
+
reference_datetime="2024-12-26T12:34:35", secondary_datetime="2025-01-07T12:34:34",
|
|
619
|
+
lat_grid=lat_grid, lon_grid=lon_grid,
|
|
620
|
+
reference_orbit_file="ref.EOF", secondary_orbit_file="sec.EOF",
|
|
621
|
+
)
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
### High-level workflow — search to interferogram in a handful of calls
|
|
625
|
+
|
|
626
|
+
```python
|
|
627
|
+
from pygeofetch.insar import InSARProject
|
|
628
|
+
from pygeofetch.models import BoundingBox
|
|
629
|
+
|
|
630
|
+
project = InSARProject(
|
|
631
|
+
name="my_aoi", aoi=BoundingBox(min_lon=-99.183, max_lon=-99.003, min_lat=19.278, max_lat=19.438),
|
|
632
|
+
output_dir="data/my_aoi_insar",
|
|
633
|
+
)
|
|
634
|
+
project.search(start_date="2024-11-01", end_date="2025-01-15") # real search, real map
|
|
635
|
+
project.download_and_extract(max_scenes=6) # real download + AOI crop
|
|
636
|
+
project.form_all_interferograms() # full verified pipeline
|
|
637
|
+
project.summary()
|
|
638
|
+
```
|
|
639
|
+
|
|
518
640
|
### Full chain, search to SBAS
|
|
519
|
-
|
|
641
|
+
|
|
520
642
|
```python
|
|
521
643
|
from pathlib import Path
|
|
522
644
|
import numpy as np
|
|
@@ -530,15 +652,15 @@ from pygeofetch.insar import (
|
|
|
530
652
|
PhaseUnwrapper, SBASTimeSeries, DataValidator, multilook,
|
|
531
653
|
)
|
|
532
654
|
from pygeofetch.insar.timeseries import InterferogramPair
|
|
533
|
-
|
|
655
|
+
|
|
534
656
|
client = PyGeoFetch()
|
|
535
657
|
client.add_credentials("copernicus", username="you@example.com", password="...")
|
|
536
658
|
client.add_credentials("opentopography", api_key="...")
|
|
537
|
-
|
|
659
|
+
|
|
538
660
|
aoi = BoundingBox(min_lon=-1.75, max_lon=-1.63, min_lat=6.15, max_lat=6.24)
|
|
539
661
|
output_dir = Path("./insar_output")
|
|
540
|
-
|
|
541
|
-
# Search — real geometry/bbox filtering
|
|
662
|
+
|
|
663
|
+
# Search — real geometry/bbox filtering
|
|
542
664
|
scenes = {}
|
|
543
665
|
for start, end in [("2026-01-01", "2026-01-08"), ("2026-01-13", "2026-01-20")]:
|
|
544
666
|
results = client.search(
|
|
@@ -548,14 +670,14 @@ for start, end in [("2026-01-01", "2026-01-08"), ("2026-01-13", "2026-01-20")]:
|
|
|
548
670
|
)
|
|
549
671
|
if results:
|
|
550
672
|
scenes[str(results[0].datetime.date())] = results[0]
|
|
551
|
-
|
|
673
|
+
|
|
552
674
|
# Download
|
|
553
675
|
downloads = {
|
|
554
676
|
label: client.download([scene], destination=output_dir / "raw" / label,
|
|
555
677
|
options=DownloadOptions(resume=True))[0]
|
|
556
678
|
for label, scene in scenes.items()
|
|
557
679
|
}
|
|
558
|
-
|
|
680
|
+
|
|
559
681
|
# Real orbit files — use the real product name, not the catalog ID
|
|
560
682
|
orbits = {
|
|
561
683
|
label: fetch_orbit_file(
|
|
@@ -564,7 +686,7 @@ orbits = {
|
|
|
564
686
|
)
|
|
565
687
|
for label, scene in scenes.items()
|
|
566
688
|
}
|
|
567
|
-
|
|
689
|
+
|
|
568
690
|
# Real DEM, clipped to the AOI
|
|
569
691
|
dem_result = client.download(
|
|
570
692
|
client.search(SearchQuery(bbox=aoi), providers=["opentopography"])[:1],
|
|
@@ -572,7 +694,7 @@ dem_result = client.download(
|
|
|
572
694
|
)[0]
|
|
573
695
|
dem_path = Preprocessor().clip(dem_result.output_path, bbox=aoi,
|
|
574
696
|
output=str(output_dir / "dem" / "clipped.tif")).output_path
|
|
575
|
-
|
|
697
|
+
|
|
576
698
|
# AOI-cropped extraction (not the full sub-swath)
|
|
577
699
|
extractor = SLCExtractor(polarisation="VV")
|
|
578
700
|
slcs = {
|
|
@@ -581,7 +703,7 @@ slcs = {
|
|
|
581
703
|
for label, dl in downloads.items()
|
|
582
704
|
}
|
|
583
705
|
dates = sorted(slcs)
|
|
584
|
-
|
|
706
|
+
|
|
585
707
|
# Interferogram formation — real orbit-based coregistration when all four
|
|
586
708
|
# inputs are available; falls back to shape-based resampling otherwise
|
|
587
709
|
gen = InterferogramGenerator(coherence_window=5, esd_enabled=True, use_gpu=False)
|
|
@@ -593,20 +715,20 @@ result = gen.process_pair(
|
|
|
593
715
|
reference_orbit_file=orbits[d1], secondary_orbit_file=orbits[d2],
|
|
594
716
|
)
|
|
595
717
|
result.save(output_dir / "interferograms", auto_visualize=True)
|
|
596
|
-
|
|
718
|
+
|
|
597
719
|
# Atmospheric correction — return_metadata=True to know what actually happened
|
|
598
720
|
atm = AtmosphericCorrector(method="elevation")
|
|
599
721
|
corrected_phase, atm_meta = atm.correct(
|
|
600
722
|
np.angle(result.interferogram), dem=dem_path, return_metadata=True
|
|
601
723
|
)
|
|
602
|
-
|
|
724
|
+
|
|
603
725
|
# Unwrapping — multilook first; wrapped_phase must be explicit (True for
|
|
604
726
|
# phase, False for coherence — never guessed from dtype)
|
|
605
727
|
phase_ml = multilook(corrected_phase, 4, 1, wrapped_phase=True)
|
|
606
728
|
coherence_ml = multilook(result.coherence, 4, 1, wrapped_phase=False)
|
|
607
729
|
unwrapper = PhaseUnwrapper(cost_mode="defo", init_method="mcf")
|
|
608
730
|
unwrapped, conncomp = unwrapper.unwrap(phase_ml, coherence_ml, nlooks=4.0)
|
|
609
|
-
|
|
731
|
+
|
|
610
732
|
# SBAS inversion
|
|
611
733
|
pairs = [InterferogramPair(d1, d2, unwrapped, coherence_ml)]
|
|
612
734
|
network_check = DataValidator.validate_sbas_network(pairs, dates)
|
|
@@ -615,12 +737,13 @@ ts_result = sbas.invert(pairs, reference_pixel=(0, 0))
|
|
|
615
737
|
ts_result.save(output_dir / "timeseries", auto_visualize=True)
|
|
616
738
|
print(f"Mean velocity: {ts_result.velocity.mean()*1000:.1f} mm/year")
|
|
617
739
|
```
|
|
618
|
-
|
|
740
|
+
|
|
619
741
|
<!-- A real, runnable two-date example — extend the search date list and repeat
|
|
620
742
|
the interferogram/unwrapping steps per consecutive pair for a full SBAS
|
|
621
|
-
network. See
|
|
622
|
-
|
|
623
|
-
|
|
743
|
+
network. See the notebooks table below for complete, real, multi-date
|
|
744
|
+
worked examples of this exact chain, including two real, published
|
|
745
|
+
volcanic and seismic deformation events. -->
|
|
746
|
+
|
|
624
747
|
---
|
|
625
748
|
|
|
626
749
|
## 🖥️ Complete CLI Reference
|
|
@@ -746,7 +869,7 @@ COMPLETION
|
|
|
746
869
|
| Notebook | Topics |
|
|
747
870
|
|---|---|
|
|
748
871
|
| `01_getting_started.ipynb` | Install, doctor, first search, first download |
|
|
749
|
-
| `02_authentication_and_providers.ipynb` | All
|
|
872
|
+
| `02_authentication_and_providers.ipynb` | All 24 providers, credentials, capability filters |
|
|
750
873
|
| `03_advanced_search.ipynb` | Federated search, CQL2 filters, 7 output formats, caching |
|
|
751
874
|
| `04_download_and_postprocessing.ipynb` | Band selection, parallel downloads, post-processing |
|
|
752
875
|
| `05_pipelines_and_scheduling.ipynb` | YAML pipelines, scheduling, Python builder API |
|
|
@@ -754,6 +877,9 @@ COMPLETION
|
|
|
754
877
|
| `07_copernicus_and_authenticated_providers.ipynb` | Copernicus, USGS, NASA, Planet, ASF, OpenTopography |
|
|
755
878
|
| `08_cli_complete_reference.ipynb` | Every CLI command with runnable examples |
|
|
756
879
|
| `09_processing_complete.ipynb` | Full processing engine: preprocessing, indices, SAR, pipelines |
|
|
880
|
+
| `piton_fournaise_full.ipynb` | Real, verified InSAR pipeline against the real April 2021 Piton de la Fournaise eruption (Réunion Island) — real pygeofetch search/download throughout, full burst-aware coregistration, real flat-earth and ERA5 correction |
|
|
881
|
+
| `amatrice_full.ipynb` | Real, verified InSAR pipeline against the real 2016 Amatrice, Italy earthquake, using the exact real interferometric pair dates from a published processing archive |
|
|
882
|
+
| `provider_search_footprint_test.ipynb` | Real search and footprint-map display validation across all 24 providers, one fully explicit, independently-runnable cell per provider |
|
|
757
883
|
|
|
758
884
|
```bash
|
|
759
885
|
cd notebooks/
|
|
@@ -762,30 +888,11 @@ jupyter lab
|
|
|
762
888
|
|
|
763
889
|
---
|
|
764
890
|
|
|
765
|
-
<p align="center">
|
|
766
|
-
<img src="docs/images/trend_map.png" width="48%" />
|
|
767
|
-
<img src="docs/images/trend_classification.png" width="48%" />
|
|
768
|
-
</p>
|
|
769
|
-
<p align="center"><em>NDVI trend (2018–2024) and severity classification for the Obuasi Municipal District, computed end-to-end with PyGeoFetch — real USGS Landsat data, boundary-clipped before processing.</em></p>
|
|
770
|
-
|
|
771
|
-
32.0% of the Obuasi Municipal District shows measurable vegetation decline over 2018–2024 (9.2% strong decline + 22.8% moderate decline), against 57.5% stable and 10.5% showing an increasing trend.
|
|
772
|
-
|
|
773
|
-
That headline number matters less than where it's concentrated. The decline isn't scattered randomly across the district — it forms a clear, spatially coherent cluster in the western portion of the AOI (roughly west of -1.70° longitude), visible as a dense, contiguous red-and-orange zone in both the trend map and the classification map. Real land degradation signals tend to look like this — clustered along mining concessions, roads, or river corridors — whereas sensor noise or processing artifacts tend to scatter more randomly across the whole scene. The fact that this pattern holds together spatially is a reasonable indicator that it reflects something real on the ground, not just pixel-level noise.
|
|
774
|
-
|
|
775
|
-
That said, an NDVI trend map on its own can't distinguish why vegetation declined — illegal small-scale mining (galamsey), selective logging, agricultural land clearing, and urban expansion can all produce a similar signature. Given Obuasi's well-documented galamsey activity specifically concentrated in this district, the spatial pattern here is consistent with mining-driven clearance — but confirming that specific cause would need either higher-resolution imagery, ground verification, or cross-referencing against known concession boundaries, not this analysis alone.
|
|
776
|
-
|
|
777
|
-
Two things worth flagging honestly rather than glossing over:
|
|
778
|
-
|
|
779
|
-
The scattered dark-blue linear and blob features running through the map (most visibly the river-like feature crossing the upper-central area) are very likely water bodies, not vegetation gain. NDVI trend over open water isn't a meaningful signal — surface reflectance there is driven by turbidity and water level, not plant health — so those features should be excluded from the "increasing" interpretation, not read as reforestation.
|
|
780
|
-
The small white gaps scattered through the trend map (several distinct circular patches) are nodata — pixels that didn't have enough valid, cloud-free observations across all six dates to fit a reliable trend. Worth being upfront that the 32%/57.5%/10.5% breakdown is computed over the valid pixels only, not the full district area including these gaps.
|
|
781
|
-
|
|
782
|
-
The eastern two-thirds of the district, by contrast, is overwhelmingly stable (dominant green in the classification map), which is itself a useful negative result — it suggests the decline is genuinely localized to a specific area rather than reflecting a district-wide drought or seasonal artifact that would show up everywhere.
|
|
783
|
-
|
|
784
891
|
## 📋 Documentation
|
|
785
892
|
|
|
786
893
|
Full documentation: **https://appiahkubis14.github.io/pygeofetch-docs/**
|
|
787
894
|
|
|
788
|
-
Covers: CLI reference · provider auth guides · pipeline configuration · post-processing catalogue · contributing guide.
|
|
895
|
+
Covers: CLI reference · provider auth guides · pipeline configuration · post-processing catalogue · InSAR verification methodology · contributing guide.
|
|
789
896
|
|
|
790
897
|
---
|
|
791
898
|
|
|
@@ -793,10 +900,10 @@ Covers: CLI reference · provider auth guides · pipeline configuration · post-
|
|
|
793
900
|
|
|
794
901
|
Contributions of all kinds are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for full guidelines.
|
|
795
902
|
|
|
796
|
-
Good first issues include implementing stub providers to full API integrations, improving test coverage, and adding new post-processing actions.
|
|
903
|
+
Good first issues include implementing stub providers to full API integrations, extending real footprint geometry support to the remaining bbox-only providers, improving test coverage, and adding new post-processing actions.
|
|
797
904
|
|
|
798
905
|
```bash
|
|
799
|
-
git clone
|
|
906
|
+
git clone git@github.com:EOCoreINT/pygeofetch.git
|
|
800
907
|
cd pygeofetch
|
|
801
908
|
pip install -e ".[dev,all]"
|
|
802
909
|
pytest tests/unit/ -v
|
|
@@ -808,9 +915,4 @@ pytest tests/unit/ -v
|
|
|
808
915
|
|
|
809
916
|
pygeofetch is free and open source software, licensed under the [MIT License](LICENSE).
|
|
810
917
|
|
|
811
|
-
© 2026 Samuel Appiah Kubi. Part of the **PyGeoVision** platform — [pygeofetch](https://github.com/appiahkubis14/pygeofetch) (data + processing)
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
918
|
+
© 2026 Samuel Appiah Kubi. Part of the **PyGeoVision** platform — [pygeofetch](https://github.com/appiahkubis14/pygeofetch) (data + processing) — complete Earth observation pipeline.
|