easy-eo 0.1.0__tar.gz → 0.2.0__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.
- easy_eo-0.2.0/.gitignore +42 -0
- easy_eo-0.2.0/PKG-INFO +176 -0
- easy_eo-0.2.0/README.md +117 -0
- easy_eo-0.2.0/eeo/__init__.py +41 -0
- easy_eo-0.2.0/eeo/_optional.py +65 -0
- easy_eo-0.2.0/eeo/_show_versions.py +101 -0
- easy_eo-0.2.0/eeo/analysis/__init__.py +33 -0
- easy_eo-0.2.0/eeo/analysis/indices.py +766 -0
- easy_eo-0.2.0/eeo/analysis/stats.py +327 -0
- easy_eo-0.2.0/eeo/common.py +240 -0
- easy_eo-0.2.0/eeo/core/__init__.py +27 -0
- {easy_eo-0.1.0 → easy_eo-0.2.0}/eeo/core/adapters/__init__.py +3 -2
- easy_eo-0.2.0/eeo/core/adapters/base.py +126 -0
- {easy_eo-0.1.0 → easy_eo-0.2.0}/eeo/core/adapters/numpy.py +22 -9
- {easy_eo-0.1.0 → easy_eo-0.2.0}/eeo/core/adapters/rasterio.py +39 -24
- easy_eo-0.2.0/eeo/core/core.py +877 -0
- easy_eo-0.2.0/eeo/core/core.pyi +311 -0
- easy_eo-0.2.0/eeo/core/decorators.py +116 -0
- easy_eo-0.2.0/eeo/core/exceptions.py +63 -0
- easy_eo-0.2.0/eeo/core/loader.py +150 -0
- easy_eo-0.2.0/eeo/core/plugins.py +23 -0
- {easy_eo-0.1.0 → easy_eo-0.2.0}/eeo/core/types.py +2 -0
- easy_eo-0.2.0/eeo/datasets/__init__.py +30 -0
- easy_eo-0.2.0/eeo/datasets/_cache.py +123 -0
- easy_eo-0.2.0/eeo/datasets/_registry.py +174 -0
- easy_eo-0.2.0/eeo/datasets/_samples.py +222 -0
- easy_eo-0.2.0/eeo/io/__init__.py +18 -0
- easy_eo-0.2.0/eeo/io/stac.py +1080 -0
- easy_eo-0.2.0/eeo/io/xarray.py +434 -0
- easy_eo-0.2.0/eeo/ops/__init__.py +17 -0
- easy_eo-0.2.0/eeo/ops/algebra.py +485 -0
- easy_eo-0.2.0/eeo/ops/merge.py +256 -0
- {easy_eo-0.1.0 → easy_eo-0.2.0}/eeo/preprocessing/__init__.py +4 -2
- easy_eo-0.2.0/eeo/preprocessing/clip.py +237 -0
- easy_eo-0.2.0/eeo/preprocessing/normalize.py +161 -0
- easy_eo-0.2.0/eeo/preprocessing/reproject.py +118 -0
- easy_eo-0.2.0/eeo/preprocessing/resample.py +154 -0
- easy_eo-0.2.0/eeo/py.typed +0 -0
- easy_eo-0.2.0/eeo/viz/__init__.py +17 -0
- easy_eo-0.2.0/eeo/viz/plot.py +640 -0
- easy_eo-0.2.0/pyproject.toml +261 -0
- easy_eo-0.1.0/.gitignore +0 -28
- easy_eo-0.1.0/PKG-INFO +0 -114
- easy_eo-0.1.0/README.md +0 -67
- easy_eo-0.1.0/eeo/__init__.py +0 -20
- easy_eo-0.1.0/eeo/analysis/__init__.py +0 -13
- easy_eo-0.1.0/eeo/analysis/indices.py +0 -62
- easy_eo-0.1.0/eeo/analysis/indices.pyi +0 -35
- easy_eo-0.1.0/eeo/analysis/stats.py +0 -127
- easy_eo-0.1.0/eeo/analysis/stats.pyi +0 -99
- easy_eo-0.1.0/eeo/common.py +0 -35
- easy_eo-0.1.0/eeo/core/__init__.py +0 -11
- easy_eo-0.1.0/eeo/core/adapters/base.py +0 -94
- easy_eo-0.1.0/eeo/core/core.py +0 -198
- easy_eo-0.1.0/eeo/core/core.pyi +0 -955
- easy_eo-0.1.0/eeo/core/decorators.py +0 -52
- easy_eo-0.1.0/eeo/core/loader.py +0 -42
- easy_eo-0.1.0/eeo/core/loader.pyi +0 -41
- easy_eo-0.1.0/eeo/core/plugins.py +0 -15
- easy_eo-0.1.0/eeo/ops/__init__.py +0 -15
- easy_eo-0.1.0/eeo/ops/algebra.py +0 -170
- easy_eo-0.1.0/eeo/ops/algebra.pyi +0 -175
- easy_eo-0.1.0/eeo/ops/merge.py +0 -133
- easy_eo-0.1.0/eeo/ops/merge.pyi +0 -46
- easy_eo-0.1.0/eeo/preprocessing/clip.py +0 -136
- easy_eo-0.1.0/eeo/preprocessing/clip.pyi +0 -83
- easy_eo-0.1.0/eeo/preprocessing/normalize.py +0 -50
- easy_eo-0.1.0/eeo/preprocessing/normalize.pyi +0 -67
- easy_eo-0.1.0/eeo/preprocessing/reproject.py +0 -73
- easy_eo-0.1.0/eeo/preprocessing/reproject.pyi +0 -36
- easy_eo-0.1.0/eeo/preprocessing/resample.py +0 -81
- easy_eo-0.1.0/eeo/preprocessing/resample.pyi +0 -44
- easy_eo-0.1.0/eeo/viz/__init__.py +0 -9
- easy_eo-0.1.0/eeo/viz/plot.py +0 -284
- easy_eo-0.1.0/eeo/viz/plot.pyi +0 -163
- easy_eo-0.1.0/pyproject.toml +0 -62
- {easy_eo-0.1.0 → easy_eo-0.2.0}/LICENSE +0 -0
easy_eo-0.2.0/.gitignore
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
*.pyo
|
|
5
|
+
*.pyd
|
|
6
|
+
*.egg-info/
|
|
7
|
+
.env
|
|
8
|
+
.venv
|
|
9
|
+
|
|
10
|
+
# Builds
|
|
11
|
+
build/
|
|
12
|
+
dist/
|
|
13
|
+
|
|
14
|
+
# Data
|
|
15
|
+
data/
|
|
16
|
+
others/
|
|
17
|
+
# ...but the recorded API responses under tests/data are fixtures the suite
|
|
18
|
+
# needs, not scratch data: without them the STAC replay tests fail in CI.
|
|
19
|
+
!tests/data/
|
|
20
|
+
|
|
21
|
+
# Docs
|
|
22
|
+
docs/build/
|
|
23
|
+
|
|
24
|
+
# Tests
|
|
25
|
+
.pytest_cache/
|
|
26
|
+
.ruff_cache/
|
|
27
|
+
.mypy_cache/
|
|
28
|
+
.coverage
|
|
29
|
+
.coverage.*
|
|
30
|
+
coverage.xml
|
|
31
|
+
htmlcov/
|
|
32
|
+
|
|
33
|
+
# IDE
|
|
34
|
+
.vscode/
|
|
35
|
+
.idea/
|
|
36
|
+
|
|
37
|
+
# OS
|
|
38
|
+
.DS_Store
|
|
39
|
+
|
|
40
|
+
# Sample data (downloaded, not tracked)
|
|
41
|
+
sample-data/
|
|
42
|
+
scripts/build_sample_data.py
|
easy_eo-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: easy-eo
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: A lightweight Earth Observation utilities library for chainable raster operations
|
|
5
|
+
Project-URL: Homepage, https://github.com/tommy-burns/easy-eo
|
|
6
|
+
Project-URL: Repository, https://github.com/tommy-burns/easy-eo
|
|
7
|
+
Project-URL: Documentation, https://easy-eo.readthedocs.io
|
|
8
|
+
Project-URL: Issues, https://github.com/tommy-burns/easy-eo/issues
|
|
9
|
+
Author: Thomas Burns Botchwey
|
|
10
|
+
License: MIT License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2025 Thomas Burns Botchwey
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Keywords: earth observation,gis,raster,remote sensing
|
|
33
|
+
Classifier: Development Status :: 3 - Alpha
|
|
34
|
+
Classifier: Intended Audience :: Science/Research
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
41
|
+
Requires-Python: >=3.10
|
|
42
|
+
Requires-Dist: geopandas<2,>=1.1
|
|
43
|
+
Requires-Dist: matplotlib>=3.8
|
|
44
|
+
Requires-Dist: numpy<3,>=1.26
|
|
45
|
+
Requires-Dist: rasterio<2,>=1.4
|
|
46
|
+
Provides-Extra: dev
|
|
47
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
48
|
+
Requires-Dist: pre-commit>=3.7; extra == 'dev'
|
|
49
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
50
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
51
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
52
|
+
Provides-Extra: stac
|
|
53
|
+
Requires-Dist: planetary-computer<2,>=1.0; extra == 'stac'
|
|
54
|
+
Requires-Dist: pystac-client<1,>=0.8; extra == 'stac'
|
|
55
|
+
Provides-Extra: xarray
|
|
56
|
+
Requires-Dist: rioxarray<1,>=0.17; extra == 'xarray'
|
|
57
|
+
Requires-Dist: xarray>=2024.7; extra == 'xarray'
|
|
58
|
+
Description-Content-Type: text/markdown
|
|
59
|
+
|
|
60
|
+
# Easy-EO
|
|
61
|
+
|
|
62
|
+
<p align="center">
|
|
63
|
+
<img src=".github/assets/eeo_logo.png" alt="Easy-EO logo" width="200">
|
|
64
|
+
</p>
|
|
65
|
+
|
|
66
|
+
[](https://github.com/Tommy-Burns/easy-eo/actions/workflows/ci.yml)
|
|
67
|
+
[](https://codecov.io/gh/Tommy-Burns/easy-eo)
|
|
68
|
+
[](https://pypi.org/project/easy-eo/)
|
|
69
|
+
[](https://pypi.org/project/easy-eo/)
|
|
70
|
+
[](https://easy-eo.readthedocs.io/en/latest/?badge=latest)
|
|
71
|
+
[](https://github.com/Tommy-Burns/easy-eo/blob/main/LICENSE)
|
|
72
|
+
|
|
73
|
+
Easy-EO is a lightweight, extensible Python library for raster-based Earth Observation (EO) analysis which allows for chainable raster processing, algebra, and visualization.
|
|
74
|
+
It provides high-level abstractions over libraries such as Rasterio, NumPy, and Matplotlib, enabling users to perform common earth-observation analyses and visualization tasks efficiently, without dealing with the underlying complexity.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Features
|
|
79
|
+
|
|
80
|
+
- Raster operations with spatial awareness
|
|
81
|
+
- Algebraic operations (`add`, `subtract`, `multiply`, `divide`)
|
|
82
|
+
- Spectral index library (`ndvi`, `ndwi`, `ndmi`, `ndbi`, `evi`, `savi`)
|
|
83
|
+
- Resampling, reprojection, and alignment
|
|
84
|
+
- Clip rasters using vectors or bounding boxes
|
|
85
|
+
- Normalization (min-max, percentile, z-score)
|
|
86
|
+
- Named bands - address bands by name anywhere an index is accepted
|
|
87
|
+
- STAC data access - search and load Sentinel-2/Landsat scenes, reading only the area of interest
|
|
88
|
+
- xarray interoperability (`to_xarray()` / `from_xarray()`)
|
|
89
|
+
- Hosted sample dataset, one call away (`eeo.datasets.load_sample_dataset()`)
|
|
90
|
+
- Visualization helpers (bands, composites, histograms)
|
|
91
|
+
- Backend-aware design (currently NumPy and Rasterio)
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Installation
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
conda create -n env_name python=3.10
|
|
99
|
+
conda activate env_name
|
|
100
|
+
pip install easy-eo
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Quick Example
|
|
104
|
+
```python
|
|
105
|
+
from eeo import load_raster
|
|
106
|
+
|
|
107
|
+
ds_nir = load_raster("path/to/nir.tif")
|
|
108
|
+
ds_red = load_raster("path/to/red.tif")
|
|
109
|
+
|
|
110
|
+
# Chainable example: clip -> resample -> compute NDVI -> multiply
|
|
111
|
+
result = (
|
|
112
|
+
ds_nir.clip_raster_with_bbox((0, 0, 1000, 1000))
|
|
113
|
+
.resample(scale_factor=2)
|
|
114
|
+
.normalized_difference(ds_red)
|
|
115
|
+
.multiply(100)
|
|
116
|
+
)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
***Or try with a hosted sample data***
|
|
120
|
+
```python
|
|
121
|
+
from eeo.datasets import load_sample_dataset
|
|
122
|
+
from eeo import load_raster
|
|
123
|
+
|
|
124
|
+
sd = load_sample_dataset()
|
|
125
|
+
|
|
126
|
+
scene = load_raster(sd.sentinel2_cog_stacked) # red, green, blue, nir bands
|
|
127
|
+
|
|
128
|
+
ndvi = scene.ndvi(red="red", nir="nir")
|
|
129
|
+
ndvi.plot_raster()
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Tutorials
|
|
133
|
+
|
|
134
|
+
Sixteen runnable notebooks live in [`examples/`](examples/README.md), from first
|
|
135
|
+
install through to complete analyses (flood mapping, drought stress, land cover,
|
|
136
|
+
terrain). Each one opens in Colab with no local setup — the first cell installs
|
|
137
|
+
Easy-EO when it detects Colab:
|
|
138
|
+
|
|
139
|
+
| | |
|
|
140
|
+
| --- | --- |
|
|
141
|
+
| [Quickstart: NDVI](examples/00_getting_started/02_quickstart_ndvi.ipynb) — open a scene, compute an index, plot it | [](https://colab.research.google.com/github/Tommy-Burns/easy-eo/blob/main/examples/00_getting_started/02_quickstart_ndvi.ipynb) |
|
|
142
|
+
| [Search and load from STAC](examples/02_data_access/02_stac_search_and_load.ipynb) — find real scenes, read them over HTTP | [](https://colab.research.google.com/github/Tommy-Burns/easy-eo/blob/main/examples/02_data_access/02_stac_search_and_load.ipynb) |
|
|
143
|
+
| [Flood mapping with NDWI](examples/03_real_world/01_flood_mapping_ndwi.ipynb) — Pakistan 2022, before/after, area affected | [](https://colab.research.google.com/github/Tommy-Burns/easy-eo/blob/main/examples/03_real_world/01_flood_mapping_ndwi.ipynb) |
|
|
144
|
+
|
|
145
|
+
The full index, including what each notebook covers, is in
|
|
146
|
+
[`examples/README.md`](examples/README.md) and in the
|
|
147
|
+
[tutorials page](https://easy-eo.readthedocs.io/en/latest/tutorials.html) of the
|
|
148
|
+
documentation.
|
|
149
|
+
|
|
150
|
+
## Supported Backends
|
|
151
|
+
| Backend | Description |
|
|
152
|
+
|----------|------------------------------------------------------|
|
|
153
|
+
| NumPy | Fast, in-memory arrays without I/O |
|
|
154
|
+
| Rasterio | Full geospatial support (CRS, transform, resampling) |
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
## Documentation
|
|
158
|
+
|
|
159
|
+
📚 Full documentation is available at:
|
|
160
|
+
|
|
161
|
+
👉 [Easy-EO Documentation](https://easy-eo.readthedocs.io/en/latest/index.html)
|
|
162
|
+
|
|
163
|
+
## Project Status
|
|
164
|
+
🚧 Active development
|
|
165
|
+
The API is stabilizing but may change before v1.0.
|
|
166
|
+
|
|
167
|
+
## Contributing
|
|
168
|
+
Contributions are welcome!
|
|
169
|
+
- Bug reports
|
|
170
|
+
- Feature requests
|
|
171
|
+
- Documentation improvements
|
|
172
|
+
|
|
173
|
+
Please open an issue or pull request on GitHub.
|
|
174
|
+
|
|
175
|
+
## License
|
|
176
|
+
MIT License © 2025 Thomas Burns Botchwey
|
easy_eo-0.2.0/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Easy-EO
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src=".github/assets/eeo_logo.png" alt="Easy-EO logo" width="200">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
[](https://github.com/Tommy-Burns/easy-eo/actions/workflows/ci.yml)
|
|
8
|
+
[](https://codecov.io/gh/Tommy-Burns/easy-eo)
|
|
9
|
+
[](https://pypi.org/project/easy-eo/)
|
|
10
|
+
[](https://pypi.org/project/easy-eo/)
|
|
11
|
+
[](https://easy-eo.readthedocs.io/en/latest/?badge=latest)
|
|
12
|
+
[](https://github.com/Tommy-Burns/easy-eo/blob/main/LICENSE)
|
|
13
|
+
|
|
14
|
+
Easy-EO is a lightweight, extensible Python library for raster-based Earth Observation (EO) analysis which allows for chainable raster processing, algebra, and visualization.
|
|
15
|
+
It provides high-level abstractions over libraries such as Rasterio, NumPy, and Matplotlib, enabling users to perform common earth-observation analyses and visualization tasks efficiently, without dealing with the underlying complexity.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- Raster operations with spatial awareness
|
|
22
|
+
- Algebraic operations (`add`, `subtract`, `multiply`, `divide`)
|
|
23
|
+
- Spectral index library (`ndvi`, `ndwi`, `ndmi`, `ndbi`, `evi`, `savi`)
|
|
24
|
+
- Resampling, reprojection, and alignment
|
|
25
|
+
- Clip rasters using vectors or bounding boxes
|
|
26
|
+
- Normalization (min-max, percentile, z-score)
|
|
27
|
+
- Named bands - address bands by name anywhere an index is accepted
|
|
28
|
+
- STAC data access - search and load Sentinel-2/Landsat scenes, reading only the area of interest
|
|
29
|
+
- xarray interoperability (`to_xarray()` / `from_xarray()`)
|
|
30
|
+
- Hosted sample dataset, one call away (`eeo.datasets.load_sample_dataset()`)
|
|
31
|
+
- Visualization helpers (bands, composites, histograms)
|
|
32
|
+
- Backend-aware design (currently NumPy and Rasterio)
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
conda create -n env_name python=3.10
|
|
40
|
+
conda activate env_name
|
|
41
|
+
pip install easy-eo
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Quick Example
|
|
45
|
+
```python
|
|
46
|
+
from eeo import load_raster
|
|
47
|
+
|
|
48
|
+
ds_nir = load_raster("path/to/nir.tif")
|
|
49
|
+
ds_red = load_raster("path/to/red.tif")
|
|
50
|
+
|
|
51
|
+
# Chainable example: clip -> resample -> compute NDVI -> multiply
|
|
52
|
+
result = (
|
|
53
|
+
ds_nir.clip_raster_with_bbox((0, 0, 1000, 1000))
|
|
54
|
+
.resample(scale_factor=2)
|
|
55
|
+
.normalized_difference(ds_red)
|
|
56
|
+
.multiply(100)
|
|
57
|
+
)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
***Or try with a hosted sample data***
|
|
61
|
+
```python
|
|
62
|
+
from eeo.datasets import load_sample_dataset
|
|
63
|
+
from eeo import load_raster
|
|
64
|
+
|
|
65
|
+
sd = load_sample_dataset()
|
|
66
|
+
|
|
67
|
+
scene = load_raster(sd.sentinel2_cog_stacked) # red, green, blue, nir bands
|
|
68
|
+
|
|
69
|
+
ndvi = scene.ndvi(red="red", nir="nir")
|
|
70
|
+
ndvi.plot_raster()
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Tutorials
|
|
74
|
+
|
|
75
|
+
Sixteen runnable notebooks live in [`examples/`](examples/README.md), from first
|
|
76
|
+
install through to complete analyses (flood mapping, drought stress, land cover,
|
|
77
|
+
terrain). Each one opens in Colab with no local setup — the first cell installs
|
|
78
|
+
Easy-EO when it detects Colab:
|
|
79
|
+
|
|
80
|
+
| | |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| [Quickstart: NDVI](examples/00_getting_started/02_quickstart_ndvi.ipynb) — open a scene, compute an index, plot it | [](https://colab.research.google.com/github/Tommy-Burns/easy-eo/blob/main/examples/00_getting_started/02_quickstart_ndvi.ipynb) |
|
|
83
|
+
| [Search and load from STAC](examples/02_data_access/02_stac_search_and_load.ipynb) — find real scenes, read them over HTTP | [](https://colab.research.google.com/github/Tommy-Burns/easy-eo/blob/main/examples/02_data_access/02_stac_search_and_load.ipynb) |
|
|
84
|
+
| [Flood mapping with NDWI](examples/03_real_world/01_flood_mapping_ndwi.ipynb) — Pakistan 2022, before/after, area affected | [](https://colab.research.google.com/github/Tommy-Burns/easy-eo/blob/main/examples/03_real_world/01_flood_mapping_ndwi.ipynb) |
|
|
85
|
+
|
|
86
|
+
The full index, including what each notebook covers, is in
|
|
87
|
+
[`examples/README.md`](examples/README.md) and in the
|
|
88
|
+
[tutorials page](https://easy-eo.readthedocs.io/en/latest/tutorials.html) of the
|
|
89
|
+
documentation.
|
|
90
|
+
|
|
91
|
+
## Supported Backends
|
|
92
|
+
| Backend | Description |
|
|
93
|
+
|----------|------------------------------------------------------|
|
|
94
|
+
| NumPy | Fast, in-memory arrays without I/O |
|
|
95
|
+
| Rasterio | Full geospatial support (CRS, transform, resampling) |
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
## Documentation
|
|
99
|
+
|
|
100
|
+
📚 Full documentation is available at:
|
|
101
|
+
|
|
102
|
+
👉 [Easy-EO Documentation](https://easy-eo.readthedocs.io/en/latest/index.html)
|
|
103
|
+
|
|
104
|
+
## Project Status
|
|
105
|
+
🚧 Active development
|
|
106
|
+
The API is stabilizing but may change before v1.0.
|
|
107
|
+
|
|
108
|
+
## Contributing
|
|
109
|
+
Contributions are welcome!
|
|
110
|
+
- Bug reports
|
|
111
|
+
- Feature requests
|
|
112
|
+
- Documentation improvements
|
|
113
|
+
|
|
114
|
+
Please open an issue or pull request on GitHub.
|
|
115
|
+
|
|
116
|
+
## License
|
|
117
|
+
MIT License © 2025 Thomas Burns Botchwey
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Easy-EO: chainable raster processing for Earth Observation.
|
|
2
|
+
|
|
3
|
+
A lightweight library of chainable raster operations, algebra, and
|
|
4
|
+
visualization built on rasterio, NumPy, GeoPandas, and matplotlib.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from . import datasets
|
|
8
|
+
from ._show_versions import show_versions
|
|
9
|
+
from .analysis import *
|
|
10
|
+
from .core import (
|
|
11
|
+
AlignmentError,
|
|
12
|
+
BackendError,
|
|
13
|
+
CRSMismatchError,
|
|
14
|
+
EEOError,
|
|
15
|
+
MissingDependencyError,
|
|
16
|
+
ValidationError,
|
|
17
|
+
load_array,
|
|
18
|
+
load_raster,
|
|
19
|
+
)
|
|
20
|
+
from .core.adapters import *
|
|
21
|
+
from .io import from_xarray, stac_search
|
|
22
|
+
from .ops import *
|
|
23
|
+
from .preprocessing import *
|
|
24
|
+
from .viz import *
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"datasets",
|
|
28
|
+
"load_raster",
|
|
29
|
+
"load_array",
|
|
30
|
+
"stac_search",
|
|
31
|
+
"from_xarray",
|
|
32
|
+
"show_versions",
|
|
33
|
+
"EEOError",
|
|
34
|
+
"ValidationError",
|
|
35
|
+
"CRSMismatchError",
|
|
36
|
+
"AlignmentError",
|
|
37
|
+
"BackendError",
|
|
38
|
+
"MissingDependencyError",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
__version__ = "0.2.0"
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Import helper for the packages behind Easy-EO's optional extras.
|
|
2
|
+
|
|
3
|
+
Heavier capabilities — STAC data access, xarray interop, the lazy backend —
|
|
4
|
+
live behind optional extras so that a plain ``pip install easy-eo`` stays
|
|
5
|
+
small. The modules implementing them import their third-party packages through
|
|
6
|
+
:func:`import_optional`, which turns a missing package into a
|
|
7
|
+
:class:`~eeo.MissingDependencyError` naming the exact install command instead
|
|
8
|
+
of a bare ``ModuleNotFoundError``.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import importlib
|
|
14
|
+
from types import ModuleType
|
|
15
|
+
|
|
16
|
+
from .core.exceptions import MissingDependencyError
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def import_optional(module: str, *, extra: str, purpose: str) -> ModuleType:
|
|
20
|
+
"""Import a module provided by an optional extra.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
module : str
|
|
25
|
+
Importable module name (e.g. ``"pystac_client"``), not the
|
|
26
|
+
distribution name.
|
|
27
|
+
extra : str
|
|
28
|
+
Name of the Easy-EO extra that provides the module (e.g. ``"stac"``),
|
|
29
|
+
used to build the ``pip install`` hint.
|
|
30
|
+
purpose : str
|
|
31
|
+
Short description of the feature needing the module (e.g. ``"STAC
|
|
32
|
+
search"``), used to open the error message.
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
ModuleType
|
|
37
|
+
The imported module.
|
|
38
|
+
|
|
39
|
+
Raises
|
|
40
|
+
------
|
|
41
|
+
MissingDependencyError
|
|
42
|
+
If the module is not installed. The message names the feature, the
|
|
43
|
+
missing package, and the ``pip install 'easy-eo[<extra>]'`` command
|
|
44
|
+
that provides it.
|
|
45
|
+
|
|
46
|
+
Examples
|
|
47
|
+
--------
|
|
48
|
+
>>> from eeo._optional import import_optional
|
|
49
|
+
>>> np = import_optional("numpy", extra="stac", purpose="STAC search")
|
|
50
|
+
>>> np.__name__
|
|
51
|
+
'numpy'
|
|
52
|
+
"""
|
|
53
|
+
try:
|
|
54
|
+
return importlib.import_module(module)
|
|
55
|
+
except ModuleNotFoundError as err:
|
|
56
|
+
# A ModuleNotFoundError raised *inside* the optional package (one of
|
|
57
|
+
# its own dependencies missing) is a different problem; report it as-is
|
|
58
|
+
# rather than blaming the package the user did install.
|
|
59
|
+
if err.name is not None and err.name.split(".")[0] != module.split(".")[0]:
|
|
60
|
+
raise
|
|
61
|
+
raise MissingDependencyError(
|
|
62
|
+
f"{purpose} requires the optional '{module}' package, which is not "
|
|
63
|
+
f"installed. Install the '{extra}' extra with: "
|
|
64
|
+
f"pip install 'easy-eo[{extra}]'"
|
|
65
|
+
) from err
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Environment reporting for bug reports and support requests."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import platform
|
|
6
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
7
|
+
|
|
8
|
+
# Optional dependencies that back the planned optional extras. Reported so a
|
|
9
|
+
# bug report shows which extras are active. Maps the display label to the
|
|
10
|
+
# installed distribution name.
|
|
11
|
+
_OPTIONAL_DISTRIBUTIONS = {
|
|
12
|
+
"xarray": "xarray",
|
|
13
|
+
"rioxarray": "rioxarray",
|
|
14
|
+
"dask": "dask",
|
|
15
|
+
"pystac-client": "pystac-client",
|
|
16
|
+
"planetary-computer": "planetary-computer",
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _distribution_version(name: str) -> str:
|
|
21
|
+
"""Return an installed distribution's version, or ``"not installed"``.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
name : str
|
|
26
|
+
Distribution (PyPI) name to look up.
|
|
27
|
+
|
|
28
|
+
Returns
|
|
29
|
+
-------
|
|
30
|
+
str
|
|
31
|
+
The installed version string, or ``"not installed"`` if the
|
|
32
|
+
distribution is not present.
|
|
33
|
+
"""
|
|
34
|
+
try:
|
|
35
|
+
return version(name)
|
|
36
|
+
except PackageNotFoundError:
|
|
37
|
+
return "not installed"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _get_versions() -> dict[str, str]:
|
|
41
|
+
"""Collect version information for Easy-EO and its dependencies.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
dict of str to str
|
|
46
|
+
Ordered mapping of component name to version string. Covers easy-eo,
|
|
47
|
+
the Python runtime and platform, the core geospatial stack (rasterio,
|
|
48
|
+
GDAL, numpy, geopandas, matplotlib), and each optional-extra
|
|
49
|
+
dependency (reported as ``"not installed"`` when absent).
|
|
50
|
+
"""
|
|
51
|
+
# Imported lazily to keep `import eeo` light; all are hard dependencies.
|
|
52
|
+
import geopandas
|
|
53
|
+
import matplotlib
|
|
54
|
+
import numpy
|
|
55
|
+
import rasterio
|
|
56
|
+
|
|
57
|
+
gdal_version = getattr(rasterio, "__gdal_version__", None) or rasterio.gdal_version()
|
|
58
|
+
|
|
59
|
+
info = {
|
|
60
|
+
"easy-eo": _distribution_version("easy-eo"),
|
|
61
|
+
"python": platform.python_version(),
|
|
62
|
+
"OS": f"{platform.system()} {platform.release()}",
|
|
63
|
+
"rasterio": rasterio.__version__,
|
|
64
|
+
"GDAL": str(gdal_version),
|
|
65
|
+
"numpy": numpy.__version__,
|
|
66
|
+
"geopandas": geopandas.__version__,
|
|
67
|
+
"matplotlib": matplotlib.__version__,
|
|
68
|
+
}
|
|
69
|
+
for label, dist in _OPTIONAL_DISTRIBUTIONS.items():
|
|
70
|
+
info[label] = _distribution_version(dist)
|
|
71
|
+
return info
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def show_versions() -> None:
|
|
75
|
+
"""Print Easy-EO, Python, and dependency version information.
|
|
76
|
+
|
|
77
|
+
Writes a human-readable report to standard output covering easy-eo, the
|
|
78
|
+
Python runtime and operating system, the core geospatial stack (rasterio,
|
|
79
|
+
GDAL, numpy, geopandas, matplotlib), and the optional-extra dependencies
|
|
80
|
+
(each shown as its version or ``not installed``). Intended for pasting
|
|
81
|
+
into bug reports.
|
|
82
|
+
|
|
83
|
+
Returns
|
|
84
|
+
-------
|
|
85
|
+
None
|
|
86
|
+
The report is printed; nothing is returned.
|
|
87
|
+
|
|
88
|
+
Examples
|
|
89
|
+
--------
|
|
90
|
+
>>> import eeo
|
|
91
|
+
>>> eeo.show_versions() # doctest: +SKIP
|
|
92
|
+
Easy-EO version information
|
|
93
|
+
...
|
|
94
|
+
"""
|
|
95
|
+
info = _get_versions()
|
|
96
|
+
width = max(len(name) for name in info)
|
|
97
|
+
|
|
98
|
+
lines = ["Easy-EO version information", "=========================="]
|
|
99
|
+
for name, value in info.items():
|
|
100
|
+
lines.append(f"{name:<{width}} : {value}")
|
|
101
|
+
print("\n".join(lines))
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Analysis operations: spectral indices and pixel statistics."""
|
|
2
|
+
|
|
3
|
+
from .indices import (
|
|
4
|
+
evi,
|
|
5
|
+
ndbi,
|
|
6
|
+
ndmi,
|
|
7
|
+
ndvi,
|
|
8
|
+
ndwi,
|
|
9
|
+
normalized_difference,
|
|
10
|
+
savi,
|
|
11
|
+
)
|
|
12
|
+
from .stats import (
|
|
13
|
+
extract_value_at_coordinate,
|
|
14
|
+
get_maximum_pixel,
|
|
15
|
+
get_mean_pixel,
|
|
16
|
+
get_minimum_pixel,
|
|
17
|
+
get_percentile_pixel,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"extract_value_at_coordinate",
|
|
22
|
+
"normalized_difference",
|
|
23
|
+
"ndvi",
|
|
24
|
+
"ndwi",
|
|
25
|
+
"ndmi",
|
|
26
|
+
"ndbi",
|
|
27
|
+
"evi",
|
|
28
|
+
"savi",
|
|
29
|
+
"get_minimum_pixel",
|
|
30
|
+
"get_percentile_pixel",
|
|
31
|
+
"get_mean_pixel",
|
|
32
|
+
"get_maximum_pixel",
|
|
33
|
+
]
|