spyndex


Namespyndex JSON
Version 0.6.0 PyPI version JSON
download
home_pagehttps://github.com/awesome-spectral-indices/spyndex
SummaryAwesome Spectral Indices in Python
upload_time2024-05-18 09:16:58
maintainerNone
docs_urlNone
authorDavid Montero Loaiza
requires_pythonNone
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <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"
}
        
Elapsed time: 3.00390s