spyndex: Awesome Spectral Indices in Python

repository·main·Indexed 42 days ago

https://github.com/awesome-spectral-indices/spyndex

A Python package for computing spectral indices from the 'Awesome Spectral Indices' list. Version 0.12.0. It supports any object with overloaded mathematical operators, including NumPy, Pandas, Xarray, Dask, CuPy, and Google Earth Engine. Key features include the computeIndex() function for batch calculations, a comprehensive library of index classes in spyndex.indices, and visualization tools via spyndex.plot.heatmap().

Tokens
14.1K
Snippets
58
Records
66
Agent score
52%

What's inside spyndex

  1. How spyndex operator overloading works

    main

    Spyndex relies on Python's overloaded operators (+, -, /, *, **) to evaluate spectral index formulas. This means any object that behaves like a mathematical number or array can be used as an input.

    Supported Object Classes

    • float / numpy.float*
    • int / numpy.int*
    • numpy.ndarray
    • pandas.Series / geopandas
    • xarray.DataArray
    • ee.Image / ee.Number (via eemont and earthengine-api)
    • dask.Array / dask.Series (via dask-array and dask-dataframe extras)

    ⚠️ Critical Warning

    Do not use Python list objects. In Python, the + operator on a list performs concatenation rather than mathematical addition. You must convert lists to numpy.ndarray or other supported types before passing them to spyndex.

  2. Access default constants and band parameters

    main

    Spyndex provides two helper Box objects for metadata:

    • spyndex.constants: Contains default values for constants required by certain indices (e.g., L for Canopy Background Adjustment). Use .default to retrieve the value.
    • spyndex.bands: Contains standard band parameter descriptions (e.g., B for Blue band).
    import spyndex
    
    # Constants
    spyndex.constants.L.default
    
    # Bands
    spyndex.bands.B
  3. Explore spectral indices and their attributes

    main

    You can explore the available spectral indices via the spyndex.indices object. This is a Box object that allows you to access indices using either string keys or dot notation. Each index object contains metadata such as its formula and reference.

    import spyndex
    
    # Access all indices
    spyndex.indices
    
    # Access a specific index (NDVI)
    spyndex.indices["NDVI"]
    spyndex.indices.NDVI
    
    # Access index attributes
    spyndex.indices.NDVI.formula
    spyndex.indices.NDVI.reference
  4. How spyndex works with overloaded operators

    main

    Spyndex relies on Python's overloaded operators (+, -, /, *, **) to evaluate spectral index formulas. This means any object class that supports these mathematical operations can be used with spyndex.

    Supported Object Classes:

    • float and int (Python built-ins)
    • numpy.ndarray and numpy.float*/numpy.int*
    • pandas.Series and geopandas objects
    • xarray.DataArray
    • ee.Image and ee.Number (Google Earth Engine)
    • dask.Array and dask.Series (requires dask-array or dask-dataframe extras)
    • cupy.ndarray (for GPU acceleration via cupy or cupy-xarray)

    Warning: Do not use standard Python list objects directly, as the + operator performs concatenation rather than mathematical addition. Convert lists to numpy.ndarray before use.

  5. GPU-accelerated computing with CuPy

    main

    Spyndex supports GPU acceleration via cupy. You can pass cupy.ndarray objects directly to computeIndex(). For xarray users, cupy-xarray can be used to convert datasets to CuPy-backed objects, and .as_numpy() can be used to convert results back to CPU memory.

    import spyndex
    import cupy as cp
    import cupy_xarray
    
    # Using raw CuPy arrays
    N = cp.random.normal(0.6, 0.10, 10000)
    R = cp.random.normal(0.1, 0.05, 10000)
    idx = spyndex.computeIndex(index="NDVI", N=N, R=R)
    
    # Using cupy-xarray with xarray
    snt_cupy = snt.cupy.as_cupy() / 10000
    idx_cupy = spyndex.computeIndex(
        index = ["NDVI", "GNDVI", "SAVI"],
        params = {
            "N": snt_cupy.sel(band = "B08"),
            "R": snt_cupy.sel(band = "B04"),
            "G": snt_cupy.sel(band = "B03"),
            "L": 0.5
        }
    )
    idx = idx_cupy.as_numpy()
  6. Parallel processing with Dask

    main

    Spyndex is compatible with dask. You can pass dask.array or dask.dataframe objects into computeIndex(). Because Dask operates in lazy mode, you must call .compute() on the resulting object to execute the computation.

    import spyndex
    import dask.array as da
    
    dask_array = da.random.normal(0.6, 0.10, (10000, 10000), chunks=(1000, 1000))
    
    idx = spyndex.computeIndex(
        index = ["NDVI", "SAVI"],
        params = {
            "N": dask_array[0],
            "R": dask_array[1],
            "L": 0.5
        }
    )
    
    # Execute the lazy computation
    idx.compute()
  7. Install spyndex

    main

    You can install spyndex via PyPI or Conda. To include support for specific array or dataframe libraries, use the corresponding extras.

    Standard Installation

    pip install spyndex

    Optional Extras

    • numpy: pip install "spyndex[numpy]"
    • pandas: pip install "spyndex[pandas]"
    • xarray: pip install "spyndex[xarray]"
    • dask-array: pip install "spyndex[dask-array]"
    • dask-dataframe: pip install "spyndex[dask-dataframe]"
    • plot: pip install "spyndex[plot]"
    • ee (Earth Engine): pip install "spyndex[ee]"
  8. Install optional spyndex extras

    main

    Spyndex supports optional dependencies for enhanced functionality with specific data structures and ecosystems:

    • numpy: Support for numpy arrays
    • pandas: Support for pandas DataFrames/Series
    • xarray: Support for xarray DataArrays
    • dask-array: Support for dask Arrays
    • dask-dataframe: Support for dask Series
    • plot: Plotting support
    • ee: Earth Engine support
    pip install "spyndex[numpy]"
    pip install "spyndex[pandas]"
    pip install "spyndex[xarray]"
    pip install "spyndex[dask-array]"
    pip install "spyndex[dask-dataframe]"
    pip install "spyndex[plot]"
    pip install "spyndex[ee]"
  9. How to use non-band constants in parameters

    main

    Some indices require parameters that are not spectral bands (e.g., the canopy background adjustment L for SAVI). You can discover the meaning of these parameters by inspecting spyndex.constants.

    For example, spyndex.constants.L provides the definition for the L parameter used in indices like SAVI or EVI.

    import spyndex
    
    # Check what 'L' represents
    print(spyndex.constants.L)
  10. How returnOrigin affects output types

    main

    When returnOrigin=True, computeIndex() attempts to return the computed indices in a format consistent with your input data. This allows for seamless integration into existing data pipelines.

    Input TypeOutput Type (if returnOrigin=True)
    pandas.Seriespandas.DataFrame
    numpy.ndarraynumpy.ndarray
    xarray.DataArrayxarray.DataArray
    ee.Imageee.Image
    ee.Numberee.List
    dask.Arraydask.Array
    dask.Seriesdask.DataFrame

    If returnOrigin=False, the function returns a standard Python list.

  11. Compute spectral indices with numpy arrays

    main

    When passing numpy.ndarray objects to spyndex.computeIndex(), the function performs element-wise computation.

    Key Behaviors:

    • Multi-index output: If you pass a list of index names (e.g., ["GLI", "VARI"]), spyndex concatenates the results along the first axis. For example, if input arrays have shape (1000,), the output for two indices will have shape (2, 1000). For 3D cubes of shape (100, 100, 100), the output will be (2, 100, 100, 100).
    • Shape Consistency: All numpy.ndarray parameters must have the same shape. Providing arrays with mismatched shapes will result in an error.
    • Constants: You can mix numpy.ndarray objects with scalar constants (e.g., 0.23) in the parameters dictionary. The resulting array shape will follow the shape of the input arrays.
    import spyndex
    import numpy as np
    
    # Simulate arrays
    BLUE = np.random.normal(0.13, 0.05, (100, 100, 100))
    GREEN = np.random.normal(0.23, 0.06, (100, 100, 100))
    RED = np.random.normal(0.14, 0.07, (100, 100, 100))
    
    # Mix arrays with a scalar constant
    parameters = {"B": BLUE, "G": 0.23, "R": RED}
    
    # Compute multiple indices
    idx = spyndex.computeIndex(["GLI", "VARI"], parameters)
    print(f"idx shape: {idx.shape}") # Output: (2, 100, 100, 100)