<p align="center">
<a href="https://github.com/davemlz/spyndex"><img src="https://raw.githubusercontent.com/davemlz/spyndex/main/docs/_static/spyndex.png" alt="spyndex"></a>
</p>
<p align="center">
<em><a href="https://github.com/davemlz/awesome-ee-spectral-indices" target="_blank">
Awesome Spectral Indices</a> in Python:</em>
</p>
<p align="center">
<b><a href="https://github.com/numpy/numpy" target="_blank">
Numpy</a> | <a href="https://github.com/pandas-dev/pandas" target="_blank">
Pandas</a> | <a href="https://github.com/geopandas/geopandas" target="_blank">
GeoPandas</a> | <a href="https://github.com/pydata/xarray" target="_blank">
Xarray</a> | <a href="https://github.com/google/earthengine-api" target="_blank">
Earth Engine</a> | <a href="https://github.com/microsoft/planetary-computer-sdk-for-python" target="_blank">
Planetary Computer</a> | <a href="https://docs.dask.org/en/latest/" target="_blank">
Dask</a> </b>
</p>
<p align="center">
<a href='https://pypi.python.org/pypi/spyndex'>
<img src='https://img.shields.io/pypi/v/spyndex.svg' alt='PyPI' />
</a>
<a href='https://anaconda.org/conda-forge/spyndex'>
<img src='https://img.shields.io/conda/vn/conda-forge/spyndex.svg' alt='conda-forge' />
</a>
<a href='https://spyndex.readthedocs.io/en/latest/?badge=latest'>
<img src='https://readthedocs.org/projects/spyndex/badge/?version=latest' alt='Documentation Status' />
</a>
<a href="https://github.com/davemlz/spyndex/actions/workflows/tests.yml" target="_blank">
<img src="https://github.com/davemlz/spyndex/actions/workflows/tests.yml/badge.svg" alt="Tests">
</a>
<a href="https://github.com/davemlz/spyndex/actions/workflows/update_awesome_spectral_indices.yml" target="_blank">
<img src="https://github.com/davemlz/spyndex/actions/workflows/update_awesome_spectral_indices.yml/badge.svg" alt="Awesome Spectral Indices">
</a>
<a href="https://opensource.org/licenses/MIT" target="_blank">
<img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License">
</a>
<a href="https://github.com/sponsors/davemlz" target="_blank">
<img src="https://img.shields.io/badge/GitHub%20Sponsors-Donate-ff69b4.svg" alt="GitHub Sponsors">
</a>
<a href="https://www.buymeacoffee.com/davemlz" target="_blank">
<img src="https://img.shields.io/badge/Buy%20me%20a%20coffee-Donate-ff69b4.svg" alt="Buy me a coffee">
</a>
<a href="https://ko-fi.com/davemlz" target="_blank">
<img src="https://img.shields.io/badge/kofi-Donate-ff69b4.svg" alt="Ko-fi">
</a>
<a href="https://twitter.com/dmlmont" target="_blank">
<img src="https://img.shields.io/twitter/follow/dmlmont?style=social" alt="Twitter">
</a>
<a href="https://github.com/psf/black" target="_blank">
<img src="https://img.shields.io/badge/code%20style-black-000000.svg" alt="Black">
</a>
<a href="https://pycqa.github.io/isort/" target="_blank">
<img src="https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336" alt="isort">
</a>
</p>
---
**GitHub**: [https://github.com/davemlz/spyndex](https://github.com/davemlz/spyndex)
**Documentation**: [https://spyndex.readthedocs.io/](https://spyndex.readthedocs.io/)
**Paper**: [https://doi.org/10.1038/s41597-023-02096-0](https://doi.org/10.1038/s41597-023-02096-0)
**PyPI**: [https://pypi.org/project/spyndex/](https://pypi.org/project/spyndex/)
**Conda-forge**: [https://anaconda.org/conda-forge/spyndex](https://anaconda.org/conda-forge/spyndex)
**Tutorials**: [https://spyndex.readthedocs.io/en/latest/tutorials.html](https://spyndex.readthedocs.io/en/latest/tutorials.html)
---
## Citation
If you use this work, please consider citing the following paper:
```bibtex
@article{montero2023standardized,
title={A standardized catalogue of spectral indices to advance the use of remote sensing in Earth system research},
author={Montero, David and Aybar, C{\'e}sar and Mahecha, Miguel D and Martinuzzi, Francesco and S{\"o}chting, Maximilian and Wieneke, Sebastian},
journal={Scientific Data},
volume={10},
number={1},
pages={197},
year={2023},
publisher={Nature Publishing Group UK London}
}
```
## Overview
The [Awesome Spectral Indices](https://github.com/davemlz/awesome-spectral-indices) is a standardized ready-to-use curated list of spectral indices
that can be used as expressions for computing spectral indices in remote sensing applications. The list was born initially to supply spectral
indices for [Google Earth Engine](https://earthengine.google.com/) through [eemont](https://github.com/davemlz/eemont) and
[spectral](https://github.com/davemlz/spectral), but given the necessity to compute spectral indices for other object classes outside the Earth
Engine ecosystem, a new package was required.
Spyndex is a python package that uses the spectral indices from the *Awesome Spectral Indices* list and creates an expression evaluation method that is
compatible with python object classes that support [overloaded operators](https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types)
(e.g. [numpy.ndarray](https://github.com/numpy/numpy), [pandas.Series](https://github.com/pandas-dev/pandas),
[xarray.DataArray](https://github.com/pydata/xarray)).
Some of the `spyndex` features are listed here:
- Access to Spectral Indices from the Awesome Spectral Indices list.
- Multiple Spectral Indices computation.
- Kernel Indices computation.
- Parallel processing.
- Compatibility with a lot of python objects!
Check the simple usage of spyndex here:
```python
import spyndex
import numpy as np
import xarray as xr
N = np.random.normal(0.6,0.10,10000)
R = np.random.normal(0.1,0.05,10000)
da = xr.DataArray(
np.array([N,R]).reshape(2,100,100),
dims = ("band","x","y"),
coords = {"band": ["NIR","Red"]}
)
idx = spyndex.computeIndex(
index = ["NDVI","SAVI"],
params = {
"N": da.sel(band = "NIR"),
"R": da.sel(band = "Red"),
"L": 0.5
}
)
```
Bands can also be passed as keywords arguments:
```python
idx = spyndex.computeIndex(
index = ["NDVI","SAVI"],
N = da.sel(band = "NIR"),
R = da.sel(band = "Red"),
L = 0.5
)
```
And indices can be computed from their class:
```python
idx = spyndex.indices.NDVI.compute(
N = da.sel(band = "NIR"),
R = da.sel(band = "Red"),
)
```
## How does it work?
Any python object class that supports overloaded operators can be used with spyndex methods.
---
*"Hey... what do you mean by 'overloaded operators'?"*
---
That's the million dollars' question! An object class that supports overloaded operators is the one that allows you to compute mathematical
operations using common operators (`+`, `-`, `/`, `*`, `**`) like `a + b`, `a + b * c` or `(a - b) / (a + b)`. You know the last one, right? That's
the formula of the famous [NDVI](https://doi.org/10.1016/0034-4257(79)90013-0).
So, if you can use the overloaded operators with an object class, you can use that class with [spyndex](https://github.com/davemlz/spyndex)!
> BE CAREFUL! Not all overloaded operators work as mathematical operators. In a `list` object class, the addition operator (`+`) concatenates two objects instead of performing an addition operation! So you must convert the `list` into a `numpy.ndarray` before using spyndex!
Here is a little list of object classes that support mathematical overloaded operators:
- `float` (Python Built-in type) or `numpy.float*` (with [numpy](https://github.com/numpy/numpy))
- `int` (Python Built-in type) or `numpy.int*` (with [numpy](https://github.com/numpy/numpy))
- `numpy.ndarray` (with [numpy](https://github.com/numpy/numpy))
- `pandas.Series` (with [pandas](https://github.com/pandas-dev/pandas) or [geopandas](https://github.com/geopandas/geopandas))
- `xarray.DataArray` (with [xarray](https://github.com/pydata/xarray))
- `ee.Image` (with [earthengine-api](https://github.com/google/earthengine-api) and [eemont](https://github.com/davemlz/eemont))
- `ee.Number` (with [earthengine-api](https://github.com/google/earthengine-api) and [eemont](https://github.com/davemlz/eemont))
And wait, there is more! If objects that support overloaded operatores can be used in spyndex, that means that you can work in **parallel**
with [dask](https://docs.dask.org/en/latest/)!
Here is the list of the dask objects that you can use with spyndex:
- `dask.Array` (with [dask](https://docs.dask.org/en/latest/))
- `dask.Series` (with [dask](https://docs.dask.org/en/latest/))
This means that you can actually use spyndex in a lot of processes! For example, you can download a Sentinel-2 image with
[sentinelsat](https://github.com/sentinelsat/sentinelsat), open and read it with [rasterio](https://github.com/mapbox/rasterio) and then compute
the desired spectral indices with [spyndex](https://github.com/davemlz/spyndex). Or you can search through the Landsat-8 STAC in the
[Planetary Computer](https://planetarycomputer.microsoft.com/) ecosystem using [pystac-client](https://github.com/stac-utils/pystac-client),
convert it to an `xarray.DataArray` with [stackstac](https://github.com/gjoseph92/stackstac) and then compute spectral indices using
[spyndex](https://github.com/davemlz/spyndex) in parallel with [dask](https://docs.dask.org/en/latest/)! Amazing, right!?
## Installation
Install the latest version from PyPI:
```
pip install spyndex
```
Upgrade spyndex by running:
```
pip install -U spyndex
```
Install the latest version from conda-forge:
```
conda install -c conda-forge spyndex
```
Install the latest dev version from GitHub by running:
```
pip install git+https://github.com/davemlz/spyndex
```
## Features
### Exploring Spectral Indices
Spectral Indices from the Awesome Spectral Indices list can be accessed through
`spyndex.indices`. This is a `Box` object where each one of the indices in the list
can be accessed as well as their [attributes](https://github.com/davemlz/awesome-ee-spectral-indices#attributes):
```python
import spyndex
# All indices
spyndex.indices
# NDVI index
spyndex.indices["NDVI"]
# Or with dot notation
spyndex.indices.NDVI
# Formula of the NDVI
spyndex.indices["NDVI"]["formula"]
# Or with dot notation
spyndex.indices.NDVI.formula
# Reference of the NDVI
spyndex.indices["NDVI"]["reference"]
# Or with dot notation
spyndex.indices.NDVI.reference
```
### Default Values
Some Spectral Indices require constant values in order to be computed. Default values
can be accessed through `spyndex.constants`. This is a `Box` object where each one
of the [constants](https://github.com/davemlz/awesome-spectral-indices#expressions) can be
accessed:
```python
import spyndex
# All constants
spyndex.constants
# Canopy Background Adjustment
spyndex.constants["L"]
# Or with dot notation
spyndex.constants.L
# Default value
spyndex.constants["L"]["default"]
# Or with dot notation
spyndex.constants.L.default
```
### Band Parameters
The standard band parameters description can be accessed through `spyndex.bands`. This is
a `Box` object where each one of the [bands](https://github.com/davemlz/awesome-spectral-indices#expressions)
can be accessed:
```python
import spyndex
# All bands
spyndex.bands
# Blue band
spyndex.bands["B"]
# Or with dot notation
spyndex.bands.B
```
### One (or more) Spectral Indices Computation
Use the `computeIndex()` method to compute as many spectral indices as you want!
The `index` parameter receives the spectral index or a list of spectral indices to
compute, while the `params` parameter receives a dictionary with the
[required parameters](https://github.com/davemlz/awesome-ee-spectral-indices#expressions)
for the spectral indices computation.
```python
import spyndex
import xarray as xr
import matplotlib.pyplot as plt
from rasterio import plot
# Open a dataset (in this case a xarray.DataArray)
snt = spyndex.datasets.open("sentinel")
# Scale the data (remember that the valid domain for reflectance is [0,1])
snt = snt / 10000
# Compute the desired spectral indices
idx = spyndex.computeIndex(
index = ["NDVI","GNDVI","SAVI"],
params = {
"N": snt.sel(band = "B08"),
"R": snt.sel(band = "B04"),
"G": snt.sel(band = "B03"),
"L": 0.5
}
)
# Plot the indices (and the RGB image for comparison)
fig, ax = plt.subplots(2,2,figsize = (10,10))
plot.show(snt.sel(band = ["B04","B03","B02"]).data / 0.3,ax = ax[0,0],title = "RGB")
plot.show(idx.sel(index = "NDVI").data,ax = ax[0,1],title = "NDVI")
plot.show(idx.sel(index = "GNDVI").data,ax = ax[1,0],title = "GNDVI")
plot.show(idx.sel(index = "SAVI").data,ax = ax[1,1],title = "SAVI")
```
<p align="center">
<a href="https://github.com/davemlz/spyndex"><img src="https://raw.githubusercontent.com/davemlz/spyndex/main/docs/_static/sentinel.png" alt="sentinel spectral indices"></a>
</p>
### Kernel Indices Computation
Use the `computeKernel()` method to compute the required kernel for kernel indices like
the kNDVI! The `kernel` parameter receives the kernel to compute, while the `params`
parameter receives a dictionary with the
[required parameters](https://github.com/davemlz/awesome-ee-spectral-indices#expressions)
for the kernel computation (e.g., `a`, `b` and `sigma` for the RBF kernel).
```python
import spyndex
import xarray as xr
import matplotlib.pyplot as plt
from rasterio import plot
# Open a dataset (in this case a xarray.DataArray)
snt = spyndex.datasets.open("sentinel")
# Scale the data (remember that the valid domain for reflectance is [0,1])
snt = snt / 10000
# Compute the kNDVI and the NDVI for comparison
idx = spyndex.computeIndex(
index = ["NDVI","kNDVI"],
params = {
# Parameters required for NDVI
"N": snt.sel(band = "B08"),
"R": snt.sel(band = "B04"),
# Parameters required for kNDVI
"kNN" : 1.0,
"kNR" : spyndex.computeKernel(
kernel = "RBF",
params = {
"a": snt.sel(band = "B08"),
"b": snt.sel(band = "B04"),
"sigma": snt.sel(band = ["B08","B04"]).mean("band")
}),
}
)
# Plot the indices (and the RGB image for comparison)
fig, ax = plt.subplots(1,3,figsize = (15,15))
plot.show(snt.sel(band = ["B04","B03","B02"]).data / 0.3,ax = ax[0],title = "RGB")
plot.show(idx.sel(index = "NDVI").data,ax = ax[1],title = "NDVI")
plot.show(idx.sel(index = "kNDVI").data,ax = ax[2],title = "kNDVI")
```
<p align="center">
<a href="https://github.com/davemlz/spyndex"><img src="https://raw.githubusercontent.com/davemlz/spyndex/main/docs/_static/kNDVI.png" alt="sentinel kNDVI"></a>
</p>
### A `pandas.DataFrame`? Sure!
No matter what kind of python object you're working with, it can be used with `spyndex` as long as it supports mathematical overloaded operators!
```python
import spyndex
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# Open a dataset (in this case a pandas.DataFrame)
df = spyndex.datasets.open("spectral")
# Compute the desired spectral indices
idx = spyndex.computeIndex(
index = ["NDVI","NDWI","NDBI"],
params = {
"N": df["SR_B5"],
"R": df["SR_B4"],
"G": df["SR_B3"],
"S1": df["SR_B6"]
}
)
# Add the land cover column to the result
idx["Land Cover"] = df["class"]
# Create a color palette for plotting
colors = ["#E33F62","#3FDDE3","#4CBA4B"]
# Plot a pairplot to check the indices behaviour
plt.figure(figsize = (15,15))
g = sns.PairGrid(idx,hue = "Land Cover",palette = sns.color_palette(colors))
g.map_lower(sns.scatterplot)
g.map_upper(sns.kdeplot,fill = True,alpha = .5)
g.map_diag(sns.kdeplot,fill = True)
g.add_legend()
plt.show()
```
<p align="center">
<a href="https://github.com/davemlz/spyndex"><img src="https://raw.githubusercontent.com/davemlz/spyndex/main/docs/_static/spectral.png" alt="landsat spectral indices"></a>
</p>
### Parallel Processing
Parallel processing is possible with `spyndex` and `dask`! You can use `dask.array` or `dask.dataframe` objects to compute spectral indices with spyndex!
If you're using `xarray`, you can also define a chunk size and work in parallel!
```python
import spyndex
import numpy as np
import dask.array as da
# Define the array shape
array_shape = (10000,10000)
# Define the chunk size
chunk_size = (1000,1000)
# Create a dask.array object
dask_array = da.array([
da.random.normal(0.6,0.10,array_shape,chunks = chunk_size),
da.random.normal(0.1,0.05,array_shape,chunks = chunk_size)
])
# "Compute" the desired spectral indices
idx = spyndex.computeIndex(
index = ["NDVI","SAVI"],
params = {
"N": dask_array[0],
"R": dask_array[1],
"L": 0.5
}
)
# Since dask works in lazy mode,
# you have to tell it that you want to compute the indices!
idx.compute()
```
### Plotting Spectral Indices
All posible values of a spectral index can be visualized using `spyndex.plot.heatmap()`! This is a module that doesn't require data,
just specify the index, the bands, and BOOM! Heatmap of all the possible values of the index!
```python
import spyndex
import matplotlib.pyplot as plt
import seaborn as sns
# Define subplots grid
fig, ax = plt.subplots(1,2,figsize = (20,8))
# Plot the NDVI with the Red values on the x-axis and the NIR on the y-axis
ax[0].set_title("NDVI heatmap with default parameters")
spyndex.plot.heatmap("NDVI","R","N",ax = ax[0])
# Keywords arguments can be passed for sns.heatmap()
ax[1].set_title("NDVI heatmap with seaborn keywords arguments")
spyndex.plot.heatmap("NDVI","R","N",annot = True,cmap = "Spectral",ax = ax[1])
plt.show()
```
<p align="center">
<a href="https://github.com/davemlz/spyndex"><img src="https://raw.githubusercontent.com/davemlz/spyndex/main/docs/_static/heatmap2.png" alt="heatmap"></a>
</p>
## License
The project is licensed under the MIT license.
## Contributing
Check the [contributing page](https://spyndex.readthedocs.io/en/latest/contributing.html).
Raw data
{
"_id": null,
"home_page": "https://github.com/awesome-spectral-indices/spyndex",
"name": "spyndex",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": null,
"author": "David Montero Loaiza",
"author_email": "dml.mont@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/82/94/d9b8f033d2f0ae3a7e6b3042ae28f90aa5901508944e643f2d011fe5b7f2/spyndex-0.6.0.tar.gz",
"platform": null,
"description": "<p align=\"center\">\n <a href=\"https://github.com/davemlz/spyndex\"><img src=\"https://raw.githubusercontent.com/davemlz/spyndex/main/docs/_static/spyndex.png\" alt=\"spyndex\"></a>\n</p>\n<p align=\"center\">\n <em><a href=\"https://github.com/davemlz/awesome-ee-spectral-indices\" target=\"_blank\">\n Awesome Spectral Indices</a> in Python:</em>\n</p>\n<p align=\"center\">\n <b><a href=\"https://github.com/numpy/numpy\" target=\"_blank\">\n Numpy</a> | <a href=\"https://github.com/pandas-dev/pandas\" target=\"_blank\">\n Pandas</a> | <a href=\"https://github.com/geopandas/geopandas\" target=\"_blank\">\n GeoPandas</a> | <a href=\"https://github.com/pydata/xarray\" target=\"_blank\">\n Xarray</a> | <a href=\"https://github.com/google/earthengine-api\" target=\"_blank\">\n Earth Engine</a> | <a href=\"https://github.com/microsoft/planetary-computer-sdk-for-python\" target=\"_blank\">\n Planetary Computer</a> | <a href=\"https://docs.dask.org/en/latest/\" target=\"_blank\">\n Dask</a> </b>\n</p>\n<p align=\"center\">\n<a href='https://pypi.python.org/pypi/spyndex'>\n <img src='https://img.shields.io/pypi/v/spyndex.svg' alt='PyPI' />\n</a>\n<a href='https://anaconda.org/conda-forge/spyndex'>\n <img src='https://img.shields.io/conda/vn/conda-forge/spyndex.svg' alt='conda-forge' />\n</a>\n<a href='https://spyndex.readthedocs.io/en/latest/?badge=latest'>\n <img src='https://readthedocs.org/projects/spyndex/badge/?version=latest' alt='Documentation Status' />\n</a>\n<a href=\"https://github.com/davemlz/spyndex/actions/workflows/tests.yml\" target=\"_blank\">\n <img src=\"https://github.com/davemlz/spyndex/actions/workflows/tests.yml/badge.svg\" alt=\"Tests\">\n</a>\n<a href=\"https://github.com/davemlz/spyndex/actions/workflows/update_awesome_spectral_indices.yml\" target=\"_blank\">\n <img src=\"https://github.com/davemlz/spyndex/actions/workflows/update_awesome_spectral_indices.yml/badge.svg\" alt=\"Awesome Spectral Indices\">\n</a>\n<a href=\"https://opensource.org/licenses/MIT\" target=\"_blank\">\n <img src=\"https://img.shields.io/badge/License-MIT-blue.svg\" alt=\"License\">\n</a>\n<a href=\"https://github.com/sponsors/davemlz\" target=\"_blank\">\n <img src=\"https://img.shields.io/badge/GitHub%20Sponsors-Donate-ff69b4.svg\" alt=\"GitHub Sponsors\">\n</a>\n<a href=\"https://www.buymeacoffee.com/davemlz\" target=\"_blank\">\n <img src=\"https://img.shields.io/badge/Buy%20me%20a%20coffee-Donate-ff69b4.svg\" alt=\"Buy me a coffee\">\n</a>\n<a href=\"https://ko-fi.com/davemlz\" target=\"_blank\">\n <img src=\"https://img.shields.io/badge/kofi-Donate-ff69b4.svg\" alt=\"Ko-fi\">\n</a>\n<a href=\"https://twitter.com/dmlmont\" target=\"_blank\">\n <img src=\"https://img.shields.io/twitter/follow/dmlmont?style=social\" alt=\"Twitter\">\n</a>\n<a href=\"https://github.com/psf/black\" target=\"_blank\">\n <img src=\"https://img.shields.io/badge/code%20style-black-000000.svg\" alt=\"Black\">\n</a>\n<a href=\"https://pycqa.github.io/isort/\" target=\"_blank\">\n <img src=\"https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336\" alt=\"isort\">\n</a>\n</p>\n\n---\n\n**GitHub**: [https://github.com/davemlz/spyndex](https://github.com/davemlz/spyndex)\n\n**Documentation**: [https://spyndex.readthedocs.io/](https://spyndex.readthedocs.io/)\n\n**Paper**: [https://doi.org/10.1038/s41597-023-02096-0](https://doi.org/10.1038/s41597-023-02096-0)\n\n**PyPI**: [https://pypi.org/project/spyndex/](https://pypi.org/project/spyndex/)\n\n**Conda-forge**: [https://anaconda.org/conda-forge/spyndex](https://anaconda.org/conda-forge/spyndex)\n\n**Tutorials**: [https://spyndex.readthedocs.io/en/latest/tutorials.html](https://spyndex.readthedocs.io/en/latest/tutorials.html)\n\n---\n\n## Citation\n\nIf you use this work, please consider citing the following paper:\n\n```bibtex\n@article{montero2023standardized,\n title={A standardized catalogue of spectral indices to advance the use of remote sensing in Earth system research},\n author={Montero, David and Aybar, C{\\'e}sar and Mahecha, Miguel D and Martinuzzi, Francesco and S{\\\"o}chting, Maximilian and Wieneke, Sebastian},\n journal={Scientific Data},\n volume={10},\n number={1},\n pages={197},\n year={2023},\n publisher={Nature Publishing Group UK London}\n}\n```\n\n## Overview\n\nThe [Awesome Spectral Indices](https://github.com/davemlz/awesome-spectral-indices) is a standardized ready-to-use curated list of spectral indices\nthat can be used as expressions for computing spectral indices in remote sensing applications. The list was born initially to supply spectral \nindices for [Google Earth Engine](https://earthengine.google.com/) through [eemont](https://github.com/davemlz/eemont) and \n[spectral](https://github.com/davemlz/spectral), but given the necessity to compute spectral indices for other object classes outside the Earth \nEngine ecosystem, a new package was required.\n\nSpyndex is a python package that uses the spectral indices from the *Awesome Spectral Indices* list and creates an expression evaluation method that is\ncompatible with python object classes that support [overloaded operators](https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types)\n(e.g. [numpy.ndarray](https://github.com/numpy/numpy), [pandas.Series](https://github.com/pandas-dev/pandas),\n[xarray.DataArray](https://github.com/pydata/xarray)).\n\nSome of the `spyndex` features are listed here:\n\n- Access to Spectral Indices from the Awesome Spectral Indices list.\n- Multiple Spectral Indices computation.\n- Kernel Indices computation.\n- Parallel processing.\n- Compatibility with a lot of python objects!\n\nCheck the simple usage of spyndex here:\n\n```python\nimport spyndex\nimport numpy as np\nimport xarray as xr\n\nN = np.random.normal(0.6,0.10,10000)\nR = np.random.normal(0.1,0.05,10000)\n\nda = xr.DataArray(\n np.array([N,R]).reshape(2,100,100),\n dims = (\"band\",\"x\",\"y\"),\n coords = {\"band\": [\"NIR\",\"Red\"]}\n)\n\nidx = spyndex.computeIndex(\n index = [\"NDVI\",\"SAVI\"],\n params = {\n \"N\": da.sel(band = \"NIR\"),\n \"R\": da.sel(band = \"Red\"),\n \"L\": 0.5\n }\n)\n```\n\nBands can also be passed as keywords arguments:\n\n```python\nidx = spyndex.computeIndex(\n index = [\"NDVI\",\"SAVI\"],\n N = da.sel(band = \"NIR\"),\n R = da.sel(band = \"Red\"),\n L = 0.5\n)\n```\n\nAnd indices can be computed from their class:\n\n```python\nidx = spyndex.indices.NDVI.compute(\n N = da.sel(band = \"NIR\"),\n R = da.sel(band = \"Red\"),\n)\n```\n\n## How does it work?\n\nAny python object class that supports overloaded operators can be used with spyndex methods.\n\n---\n\n*\"Hey... what do you mean by 'overloaded operators'?\"*\n\n---\n\nThat's the million dollars' question! An object class that supports overloaded operators is the one that allows you to compute mathematical \noperations using common operators (`+`, `-`, `/`, `*`, `**`) like `a + b`, `a + b * c` or `(a - b) / (a + b)`. You know the last one, right? That's \nthe formula of the famous [NDVI](https://doi.org/10.1016/0034-4257(79)90013-0).\n\nSo, if you can use the overloaded operators with an object class, you can use that class with [spyndex](https://github.com/davemlz/spyndex)!\n\n> BE CAREFUL! Not all overloaded operators work as mathematical operators. In a `list` object class, the addition operator (`+`) concatenates two objects instead of performing an addition operation! So you must convert the `list` into a `numpy.ndarray` before using spyndex!\n\nHere is a little list of object classes that support mathematical overloaded operators:\n\n- `float` (Python Built-in type) or `numpy.float*` (with [numpy](https://github.com/numpy/numpy))\n- `int` (Python Built-in type) or `numpy.int*` (with [numpy](https://github.com/numpy/numpy))\n- `numpy.ndarray` (with [numpy](https://github.com/numpy/numpy))\n- `pandas.Series` (with [pandas](https://github.com/pandas-dev/pandas) or [geopandas](https://github.com/geopandas/geopandas))\n- `xarray.DataArray` (with [xarray](https://github.com/pydata/xarray))\n- `ee.Image` (with [earthengine-api](https://github.com/google/earthengine-api) and [eemont](https://github.com/davemlz/eemont))\n- `ee.Number` (with [earthengine-api](https://github.com/google/earthengine-api) and [eemont](https://github.com/davemlz/eemont))\n\nAnd wait, there is more! If objects that support overloaded operatores can be used in spyndex, that means that you can work in **parallel**\nwith [dask](https://docs.dask.org/en/latest/)!\n\nHere is the list of the dask objects that you can use with spyndex:\n\n- `dask.Array` (with [dask](https://docs.dask.org/en/latest/))\n- `dask.Series` (with [dask](https://docs.dask.org/en/latest/))\n\nThis means that you can actually use spyndex in a lot of processes! For example, you can download a Sentinel-2 image with\n[sentinelsat](https://github.com/sentinelsat/sentinelsat), open and read it with [rasterio](https://github.com/mapbox/rasterio) and then compute \nthe desired spectral indices with [spyndex](https://github.com/davemlz/spyndex). Or you can search through the Landsat-8 STAC in the \n[Planetary Computer](https://planetarycomputer.microsoft.com/) ecosystem using [pystac-client](https://github.com/stac-utils/pystac-client),\nconvert it to an `xarray.DataArray` with [stackstac](https://github.com/gjoseph92/stackstac) and then compute spectral indices using\n[spyndex](https://github.com/davemlz/spyndex) in parallel with [dask](https://docs.dask.org/en/latest/)! Amazing, right!?\n\n## Installation\n\nInstall the latest version from PyPI:\n\n```\npip install spyndex\n```\n\nUpgrade spyndex by running:\n\n```\npip install -U spyndex\n```\n\nInstall the latest version from conda-forge:\n\n```\nconda install -c conda-forge spyndex\n```\n\nInstall the latest dev version from GitHub by running:\n\n```\npip install git+https://github.com/davemlz/spyndex\n```\n\n## Features\n\n### Exploring Spectral Indices\n\nSpectral Indices from the Awesome Spectral Indices list can be accessed through\n`spyndex.indices`. This is a `Box` object where each one of the indices in the list\ncan be accessed as well as their [attributes](https://github.com/davemlz/awesome-ee-spectral-indices#attributes):\n\n```python\nimport spyndex\n\n# All indices\nspyndex.indices\n\n# NDVI index\nspyndex.indices[\"NDVI\"]\n\n# Or with dot notation\nspyndex.indices.NDVI\n\n# Formula of the NDVI\nspyndex.indices[\"NDVI\"][\"formula\"]\n\n# Or with dot notation\nspyndex.indices.NDVI.formula\n\n# Reference of the NDVI\nspyndex.indices[\"NDVI\"][\"reference\"]\n\n# Or with dot notation\nspyndex.indices.NDVI.reference\n```\n\n### Default Values\n\nSome Spectral Indices require constant values in order to be computed. Default values\ncan be accessed through `spyndex.constants`. This is a `Box` object where each one\nof the [constants](https://github.com/davemlz/awesome-spectral-indices#expressions) can be\naccessed:\n\n```python\nimport spyndex\n\n# All constants\nspyndex.constants\n\n# Canopy Background Adjustment\nspyndex.constants[\"L\"]\n\n# Or with dot notation\nspyndex.constants.L\n\n# Default value\nspyndex.constants[\"L\"][\"default\"]\n\n# Or with dot notation\nspyndex.constants.L.default\n```\n\n### Band Parameters\n\nThe standard band parameters description can be accessed through `spyndex.bands`. This is \na `Box` object where each one of the [bands](https://github.com/davemlz/awesome-spectral-indices#expressions) \ncan be accessed:\n\n```python\nimport spyndex\n\n# All bands\nspyndex.bands\n\n# Blue band\nspyndex.bands[\"B\"]\n\n# Or with dot notation\nspyndex.bands.B\n```\n\n### One (or more) Spectral Indices Computation\n\nUse the `computeIndex()` method to compute as many spectral indices as you want!\nThe `index` parameter receives the spectral index or a list of spectral indices to\ncompute, while the `params` parameter receives a dictionary with the\n[required parameters](https://github.com/davemlz/awesome-ee-spectral-indices#expressions)\nfor the spectral indices computation.\n\n```python\nimport spyndex\nimport xarray as xr\nimport matplotlib.pyplot as plt\nfrom rasterio import plot\n\n# Open a dataset (in this case a xarray.DataArray)\nsnt = spyndex.datasets.open(\"sentinel\")\n\n# Scale the data (remember that the valid domain for reflectance is [0,1])\nsnt = snt / 10000\n\n# Compute the desired spectral indices\nidx = spyndex.computeIndex(\n index = [\"NDVI\",\"GNDVI\",\"SAVI\"],\n params = {\n \"N\": snt.sel(band = \"B08\"),\n \"R\": snt.sel(band = \"B04\"),\n \"G\": snt.sel(band = \"B03\"),\n \"L\": 0.5\n }\n)\n\n# Plot the indices (and the RGB image for comparison)\nfig, ax = plt.subplots(2,2,figsize = (10,10))\nplot.show(snt.sel(band = [\"B04\",\"B03\",\"B02\"]).data / 0.3,ax = ax[0,0],title = \"RGB\")\nplot.show(idx.sel(index = \"NDVI\").data,ax = ax[0,1],title = \"NDVI\")\nplot.show(idx.sel(index = \"GNDVI\").data,ax = ax[1,0],title = \"GNDVI\")\nplot.show(idx.sel(index = \"SAVI\").data,ax = ax[1,1],title = \"SAVI\")\n```\n\n<p align=\"center\">\n <a href=\"https://github.com/davemlz/spyndex\"><img src=\"https://raw.githubusercontent.com/davemlz/spyndex/main/docs/_static/sentinel.png\" alt=\"sentinel spectral indices\"></a>\n</p>\n\n### Kernel Indices Computation\n\nUse the `computeKernel()` method to compute the required kernel for kernel indices like\nthe kNDVI! The `kernel` parameter receives the kernel to compute, while the `params` \nparameter receives a dictionary with the\n[required parameters](https://github.com/davemlz/awesome-ee-spectral-indices#expressions)\nfor the kernel computation (e.g., `a`, `b` and `sigma` for the RBF kernel).\n\n```python\nimport spyndex\nimport xarray as xr\nimport matplotlib.pyplot as plt\nfrom rasterio import plot\n\n# Open a dataset (in this case a xarray.DataArray)\nsnt = spyndex.datasets.open(\"sentinel\")\n\n# Scale the data (remember that the valid domain for reflectance is [0,1])\nsnt = snt / 10000\n\n# Compute the kNDVI and the NDVI for comparison\nidx = spyndex.computeIndex(\n index = [\"NDVI\",\"kNDVI\"],\n params = {\n # Parameters required for NDVI\n \"N\": snt.sel(band = \"B08\"),\n \"R\": snt.sel(band = \"B04\"),\n # Parameters required for kNDVI\n \"kNN\" : 1.0,\n \"kNR\" : spyndex.computeKernel(\n kernel = \"RBF\",\n params = {\n \"a\": snt.sel(band = \"B08\"),\n \"b\": snt.sel(band = \"B04\"),\n \"sigma\": snt.sel(band = [\"B08\",\"B04\"]).mean(\"band\")\n }),\n }\n)\n\n# Plot the indices (and the RGB image for comparison)\nfig, ax = plt.subplots(1,3,figsize = (15,15))\nplot.show(snt.sel(band = [\"B04\",\"B03\",\"B02\"]).data / 0.3,ax = ax[0],title = \"RGB\")\nplot.show(idx.sel(index = \"NDVI\").data,ax = ax[1],title = \"NDVI\")\nplot.show(idx.sel(index = \"kNDVI\").data,ax = ax[2],title = \"kNDVI\")\n```\n\n<p align=\"center\">\n <a href=\"https://github.com/davemlz/spyndex\"><img src=\"https://raw.githubusercontent.com/davemlz/spyndex/main/docs/_static/kNDVI.png\" alt=\"sentinel kNDVI\"></a>\n</p>\n\n### A `pandas.DataFrame`? Sure!\n\nNo matter what kind of python object you're working with, it can be used with `spyndex` as long as it supports mathematical overloaded operators! \n\n```python\nimport spyndex\nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\n# Open a dataset (in this case a pandas.DataFrame)\ndf = spyndex.datasets.open(\"spectral\")\n\n# Compute the desired spectral indices\nidx = spyndex.computeIndex(\n index = [\"NDVI\",\"NDWI\",\"NDBI\"],\n params = {\n \"N\": df[\"SR_B5\"],\n \"R\": df[\"SR_B4\"],\n \"G\": df[\"SR_B3\"],\n \"S1\": df[\"SR_B6\"]\n }\n)\n\n# Add the land cover column to the result\nidx[\"Land Cover\"] = df[\"class\"]\n\n# Create a color palette for plotting\ncolors = [\"#E33F62\",\"#3FDDE3\",\"#4CBA4B\"]\n\n# Plot a pairplot to check the indices behaviour\nplt.figure(figsize = (15,15))\ng = sns.PairGrid(idx,hue = \"Land Cover\",palette = sns.color_palette(colors))\ng.map_lower(sns.scatterplot)\ng.map_upper(sns.kdeplot,fill = True,alpha = .5)\ng.map_diag(sns.kdeplot,fill = True)\ng.add_legend()\nplt.show()\n```\n\n<p align=\"center\">\n <a href=\"https://github.com/davemlz/spyndex\"><img src=\"https://raw.githubusercontent.com/davemlz/spyndex/main/docs/_static/spectral.png\" alt=\"landsat spectral indices\"></a>\n</p>\n\n### Parallel Processing\n\nParallel processing is possible with `spyndex` and `dask`! You can use `dask.array` or `dask.dataframe` objects to compute spectral indices with spyndex!\nIf you're using `xarray`, you can also define a chunk size and work in parallel!\n\n```python\nimport spyndex\nimport numpy as np\nimport dask.array as da\n\n# Define the array shape\narray_shape = (10000,10000)\n\n# Define the chunk size\nchunk_size = (1000,1000)\n\n# Create a dask.array object\ndask_array = da.array([\n da.random.normal(0.6,0.10,array_shape,chunks = chunk_size),\n da.random.normal(0.1,0.05,array_shape,chunks = chunk_size)\n])\n\n# \"Compute\" the desired spectral indices\nidx = spyndex.computeIndex(\n index = [\"NDVI\",\"SAVI\"],\n params = {\n \"N\": dask_array[0],\n \"R\": dask_array[1],\n \"L\": 0.5\n }\n)\n\n# Since dask works in lazy mode,\n# you have to tell it that you want to compute the indices!\nidx.compute()\n```\n\n### Plotting Spectral Indices\n\nAll posible values of a spectral index can be visualized using `spyndex.plot.heatmap()`! This is a module that doesn't require data,\njust specify the index, the bands, and BOOM! Heatmap of all the possible values of the index!\n\n```python\nimport spyndex\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\n# Define subplots grid\nfig, ax = plt.subplots(1,2,figsize = (20,8))\n\n# Plot the NDVI with the Red values on the x-axis and the NIR on the y-axis\nax[0].set_title(\"NDVI heatmap with default parameters\")\nspyndex.plot.heatmap(\"NDVI\",\"R\",\"N\",ax = ax[0])\n\n# Keywords arguments can be passed for sns.heatmap()\nax[1].set_title(\"NDVI heatmap with seaborn keywords arguments\")\nspyndex.plot.heatmap(\"NDVI\",\"R\",\"N\",annot = True,cmap = \"Spectral\",ax = ax[1])\n\nplt.show()\n```\n\n<p align=\"center\">\n <a href=\"https://github.com/davemlz/spyndex\"><img src=\"https://raw.githubusercontent.com/davemlz/spyndex/main/docs/_static/heatmap2.png\" alt=\"heatmap\"></a>\n</p>\n\n## License\n\nThe project is licensed under the MIT license.\n\n## Contributing\n\nCheck the [contributing page](https://spyndex.readthedocs.io/en/latest/contributing.html).\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Awesome Spectral Indices in Python",
"version": "0.6.0",
"project_urls": {
"Homepage": "https://github.com/awesome-spectral-indices/spyndex"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "8294d9b8f033d2f0ae3a7e6b3042ae28f90aa5901508944e643f2d011fe5b7f2",
"md5": "068918462be9da7cb633a1074f001781",
"sha256": "09e660d21ac065dca2d950adc67347fcb0e2d5e4439d02ea129ee35b10084445"
},
"downloads": -1,
"filename": "spyndex-0.6.0.tar.gz",
"has_sig": false,
"md5_digest": "068918462be9da7cb633a1074f001781",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 728720,
"upload_time": "2024-05-18T09:16:58",
"upload_time_iso_8601": "2024-05-18T09:16:58.476700Z",
"url": "https://files.pythonhosted.org/packages/82/94/d9b8f033d2f0ae3a7e6b3042ae28f90aa5901508944e643f2d011fe5b7f2/spyndex-0.6.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-05-18 09:16:58",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "awesome-spectral-indices",
"github_project": "spyndex",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"tox": true,
"lcname": "spyndex"
}