Skip to content

v1 Explained

Migration to v1 has started. This page documents the new schema as it exists today and will grow as additional v1 changes are implemented.

Compatibility during the migration

The existing API and v0 catalogue remain available and can continue to be used as usual. New spectral indices can also still be submitted through the normal contribution process. The v1 files are being developed in parallel so that the public API does not have to change all at once.

Table of Contents

Current status

At the present stage, v1 makes eleven changes to a spectral-index record:

  • short_name is renamed to acronym;
  • long_name is renamed to name;
  • reference is replaced by a structured source object;
  • the generated platforms property is no longer included;
  • formula bands and constants are stored separately, with contributor-defined metadata for constants;
  • formula inputs supplied outside spectral data use a dedicated external_variables property with contributor-defined descriptions;
  • source.source_companions identifies other catalogue keys generated from the same scientific source link;
  • the formula language introduces calls to min(), max(), and unary tanh();
  • contextual spatial reductions use spatial_max(), spatial_min(), and spatial_mean(), with their shared scope declared under reductions; and
  • kernel evaluations use the two-input kernel() function instead of synthetic operands such as kNN and kNR; and
  • application, generated sensing modalities, and optional index families are grouped in classification, while radar inputs use polarizations instead of being treated as bands.

Both renamed properties remain required. Neither an acronym nor a name is required to be unique, and neither one serves as the catalogue lookup key.

The current generated catalogues have:

  • 280 catalogue keys in v0 and 282 in v1, where WCI3 and CWI are currently v1-only;
  • identity values carried from short_name to acronym and from long_name to name across the 280 shared keys;
  • the former reference value retained as source.source_link, with generated link status, link type, and source-companion metadata;
  • formula inputs divided between ordered bands and polarizations arrays, a constants object, and an external_variables object containing per-index definitions;
  • contributor-provided application domains and families grouped under classification, alongside sensing modalities generated from formula standards;
  • contextual reduction operations retained directly in formula, with their dimension-level execution context stored in reductions;
  • the five kernel-index formulas expressed through kernel() calls over their underlying bands and constants instead of precomputed kernel operands;
  • identical bands.json metadata, plus v1 constants.json and external_variables.json files that group contributor-provided definitions by variable and index; and
  • a v1 CSV using acronym,name,source in place of short_name,long_name,reference, incorporating the deliberate v1 formula changes described above, and including the v1-only WCI3 and CWI records.

The two versions are generated independently and written to different locations:

VersionCatalogue JSONCatalogue CSVBand metadataConstant metadataExternal-variable metadata
v0output/spectral-indices-dict.jsonoutput/spectral-indices-table.csvoutput/bands.jsonoutput/constants.json
v1output/v1/spectral-indices-dict.jsonoutput/v1/spectral-indices-table.csvoutput/v1/bands.jsonoutput/v1/constants.jsonoutput/v1/external_variables.json

This separation allows v1 to evolve without changing the files currently used by v0 consumers.

Catalogue structure

The top-level JSON structure has not changed. The catalogue is an object with a single SpectralIndices property. Its value is an object whose keys identify the individual spectral indices:

json
{
    "SpectralIndices": {
        "SAVI": {
            ...
        },
        "NDVI": {
            ...
        }
    }
}

The outer key, such as SAVI, is the catalogue lookup key. The acronym inside the record is a separate schema property. They normally have the same value in the current catalogue, but the schema does not require them to match. Both catalogue keys and acronyms are case-sensitive.

New schema

The Soil-Adjusted Vegetation Index (SAVI) illustrates the current difference between the schemas and the full constant-definition structure.

  • v1: New schema.
  • v0: Old schema.
  • diff: Difference between schemas (red highlighting means deletion, green highlighting means addition).
json
{
    "SpectralIndices": {
        ...,
        "SAVI": {
            "acronym": "SAVI",
            "bands": [
                "N",
                "R"
            ],
            "classification": {
                "application_domain": "vegetation",
                "family": null,
                "sensing_modalities": [
                    "multispectral"
                ]
            },
            "constants": {
                "L": {
                    "default_value": 0.5,
                    "description": "Canopy background adjustment",
                    "suggested_range": [
                        0.25,
                        1
                    ],
                    "suggested_values": {
                        "High vegetation densities": 0.25,
                        "Intermediate vegetation densities": 0.5,
                        "Low vegetation densities": 1.0
                    }
                }
            },
            "contributor": "https://github.com/davemlz",
            "date_of_addition": "2021-04-07",
            "external_variables": {},
            "formula": "(1.0 + L) * (N - R) / (N + R + L)",
            "name": "Soil-Adjusted Vegetation Index",
            "polarizations": [],
            "reductions": {},
            "source": {
                "source_companions": [],
                "source_link": "https://doi.org/10.1016/0034-4257(88)90106-X",
                "source_link_status": "operational",
                "source_link_type": "doi",
                "source_type": "article"
            }
        },
        ...
    }
}
json
{
    "SpectralIndices": {
        ...,
        "SAVI": {
            "application_domain": "vegetation",
            "bands": [
                "L",
                "N",
                "R"
            ],
            "contributor": "https://github.com/davemlz",
            "date_of_addition": "2021-04-07",
            "formula": "(1.0 + L) * (N - R) / (N + R + L)",
            "long_name": "Soil-Adjusted Vegetation Index",
            "platforms": [
                "Sentinel-2",
                "Landsat-OLI",
                "Landsat-TM",
                "Landsat-ETM+",
                "MODIS",
                "Planet-Fusion"
            ],
            "reference": "https://doi.org/10.1016/0034-4257(88)90106-X",
            "short_name": "SAVI"
        },
        ...
    }
}
json
{
    "SpectralIndices": {
        ...,
        "SAVI": {
            "acronym": "SAVI", 
            "application_domain": "vegetation", 
            "bands": [
                "L", 
                "N",
                "R"
            ],
            "classification": { 
                "application_domain": "vegetation", 
                "family": null, 
                "sensing_modalities": ["multispectral"] 
            }, 
            "constants": { 
                "L": { 
                    "default_value": 0.5, 
                    "description": "Canopy background adjustment", 
                    "suggested_range": [0.25, 1], 
                    "suggested_values": { 
                        "High vegetation densities": 0.25, 
                        "Intermediate vegetation densities": 0.5, 
                        "Low vegetation densities": 1.0
                    } 
                } 
            }, 
            "contributor": "https://github.com/davemlz",
            "date_of_addition": "2021-04-07",
            "external_variables": {}, 
            "formula": "(1.0 + L) * (N - R) / (N + R + L)",
            "long_name": "Soil-Adjusted Vegetation Index", 
            "name": "Soil-Adjusted Vegetation Index", 
            "polarizations": [], 
            "platforms": [ 
                "Sentinel-2", 
                "Landsat-OLI", 
                "Landsat-TM", 
                "Landsat-ETM+", 
                "MODIS", 
                "Planet-Fusion"
            ], 
            "reference": "https://doi.org/10.1016/0034-4257(88)90106-X", 
            "reductions": {}, 
            "source": { 
                "source_companions": [], 
                "source_link": "https://doi.org/10.1016/0034-4257(88)90106-X", 
                "source_link_status": "operational", 
                "source_link_type": "doi", 
                "source_type": "article"
            }, 
            "short_name": "SAVI"
        },
        ...
    }
}

Why the identity properties were renamed

The v0 names describe the two fields relative to one another: short_name is the compact label and long_name is its expanded form. In v1, the properties state their roles directly. acronym is the abbreviation used for display and communication, while name is the human-readable name of the index.

These properties are descriptive metadata rather than catalogue identifiers. Two indices may use the same acronym, the same name, or both, including when they belong to different application domains. The surrounding key in the SpectralIndices mapping remains the exact identifier used to retrieve a record.

Both acronym and name are still required when a source definition is validated. The rename does not make either property optional and does not add any uniqueness constraint.

Why bands and constants were separated

In v0, every named formula variable is stored in a single bands array. That means physical inputs such as N, R, and B appear beside coefficients such as g, C1, C2, and L, even though they play different roles when an index is evaluated.

V1 uses separate Bands, Polarizations, Constants, and External registries. Formula variables are classified against those registries: spectral and thermal inputs are generated into bands; radar inputs are generated into polarizations; the contributor supplies metadata for every constant; and separately supplied contextual inputs are defined in external_variables. For SAVI, this produces two required bands and one configurable constant instead of one mixed three-item list.

Constant values are no longer taken from one universal metadata dictionary. Each index provides its own description and may provide its own default, so the same standard constant can be documented or initialized differently for different indices.

Why classification is structured

The v0 application_domain vocabulary mixes scientific applications with other ways of describing an index. vegetation, water, and burn describe applications, while kernel describes an index family and radar describes a sensing modality as well as the current radar family.

V1 moves the required, contributor-provided application domain into classification.application_domain. The optional contributor-provided classification.family list currently accepts kernel, tasseled_cap, and radar. All five kernel indices are classified under the vegetation application with the kernel family. All radar indices use the vegetation application except NDPolI, which uses the new geology application; all thirteen use the radar family.

classification.sensing_modalities is not submitted by contributors. The generator derives it from the formula standards and may include multispectral, thermal, or radar. A formula combining spectral and thermal inputs receives both values. The current catalogue contains 249 multispectral indices, 20 multispectral-plus-thermal indices, and 13 radar indices.

Why polarizations are separate from bands

HH, HV, VH, and VV describe radar transmit/receive polarizations, not spectral bands. V1 therefore registers them in Polarizations and writes them to the generated polarizations array. Radar-only indices have an empty bands array, while mixed formulas could populate both arrays. This separation also provides the input information used to generate the radar sensing modality.

Why external variables are separate

Some formulas require a value that is neither an observed spectral band nor a configurable mathematical coefficient. NIRvP, for example, uses photosynthetically active radiation (PAR) in addition to near-infrared and red reflectance. PAR must be supplied when evaluating the formula, but it does not have a universal catalogue default and should not be presented as a tunable constant.

V1 therefore registers PAR in the dedicated External registry. NIRvP describes it under external_variables, while bands contains only N and R and constants remains empty. This makes the source of each input clear without prescribing how consumers obtain, scale, or align the external data.

Why contextual reductions are separate

Ordinary spectral-index arithmetic is evaluated independently at every pixel. Some published indices additionally need a statistic calculated from a larger data context. CWI, for example, divides values using the maximum of S2 and the maximum of B across the area of interest. Each maximum is a scalar that is then reused for every output pixel; it is not the pointwise maximum of multiple bands.

V1 keeps S2 and B as the only operands and expresses the operations directly as spatial_max(S2) and spatial_max(B). The separate reductions property supplies the spatial context shared by those operations. This avoids creating synthetic operands such as S2_max and keeps context configuration out of the mathematical expression.

Why kernel evaluations are functions

The v0 kernel indices encode evaluated kernel terms as operands. For example, kNN means the kernel evaluated between N and N, while kNR means the kernel evaluated between N and R. Treating every pair as another band expands the supported operand registry even though these values are derived operations rather than observed inputs.

V1 expresses the operation directly as kernel(X, Y). The kNDVI formula now uses kernel(N, N) and kernel(N, R), and its generated bands array contains only the underlying N and R inputs. The same change applies to kEVI, kRVI, kVARI, and kIPVI. The former kNN, kNR, kNB, kNL, kGG, kGR, kGB, kBB, kBR, kBL, kRR, kRB, kRL, and kLL values are no longer v1 band standards.

Why platforms is absent

In v0, platforms is not authored as part of an index definition. The v0 generator derives it by comparing every variable in the formula with a hard-coded set of platform band profiles. It then attaches the resulting list to the serialized index record.

The v1 generator deliberately skips that inference step. It still parses the formula and creates bands, polarizations, constants, external_variables, and sensing modalities, but it neither calculates nor serializes platforms. Platform compatibility will be handled separately as the v1 migration develops; sensing modality should not be interpreted as a replacement list of compatible platforms.

The omission applies only to the v1 index records. v0 continues to generate platforms, so existing consumers are not required to migrate now. The absence of platforms in v1 should also not be interpreted as meaning that an index is compatible with every sensor.

Properties

Every serialized v1 index currently contains the following twelve properties:

PropertyJSON typePurpose
acronymstringConcise, case-sensitive acronym
bandsarray of stringsOrdered spectral and thermal inputs extracted from the formula
classificationobjectApplication, generated sensing modalities, and optional families
constantsobject of objectsPer-index metadata and recommendations for formula constants
contributorstringContributor's GitHub profile or email address
date_of_additionstringValid calendar date in YYYY-MM-DD form
external_variablesobject of objectsDescriptions of formula inputs supplied outside spectral data
formulastringValidated mathematical expression
namestringHuman-readable name of the index
polarizationsarray of stringsOrdered radar-polarization inputs extracted from the formula
reductionsobjectShared execution contexts for contextual formula reductions
sourceobjectScientific source and generated link metadata

Unknown properties are rejected when source definitions are validated. bands, polarizations, and classification.sensing_modalities are generated from formula. constants, external_variables, and reductions may be omitted only when the formula does not require them; when it does, the contributor must provide the corresponding definitions. Generated records use empty arrays or objects where an index has no corresponding inputs, definitions, or reduction context.

classification

json
"kNDVI": {
    ...,
    "classification": { 
        "application_domain": "vegetation", 
        "family": ["kernel"], 
        "sensing_modalities": ["multispectral"] 
    }, 
    ...
}

The object has three classification facets:

PropertyContributor-providedRequired in sourceGenerated
application_domainYesYesNo
familyYesNoNo
sensing_modalitiesNoNoYes
classification.application_domain

The broad scientific application used to organize and style the catalogue. The lowercase, case-sensitive value must be one of:

  • vegetation
  • water
  • burn
  • snow
  • soil
  • urban
  • geology
  • clouds

An index has exactly one application domain in the current schema. It is required from the contributor and does not describe a sensing modality, platform, or computational method.

classification.sensing_modalities

A generated list containing one or more of multispectral, thermal, and radar. Registered non-thermal bands produce multispectral; T, T1, and T2 produce thermal; and registered radar polarizations produce radar. The generator uses the canonical order multispectral, thermal, then radar.

The list describes required measurement types, not compatible platforms. For example, NBRT1 is generated with ["multispectral", "thermal"] because its formula combines N and S2 with T.

classification.family

An optional contributor-provided list containing one or more of kernel, tasseled_cap, and radar. Empty lists, duplicates, and unsupported values are rejected. When no family has been assigned, generated records serialize the property as null.

The family is independent of application and modality. kNDVI is in the kernel family but has vegetation as its application and multispectral as its generated sensing modality.

bands

json
"SAVI": {
    ...,
    "bands": [ 
        "N", 
        "R"
    ], 
    ...
}

An ordered list of the registered spectral and thermal inputs used by formula. Variables are recorded in the order in which they first appear, and repeated variables appear only once.

Formula constants, coefficients, and wavelength parameters are written to constants; radar inputs are written to polarizations; and inputs from the External registry are written to external_variables. A function result is not added as a band: the variables inside kernel(N, R) are extracted as N and R.

For SAVI, N and R refer to near-infrared and red inputs. Descriptions of registered bands are available in bands.json.

bands describes the inputs needed to evaluate the expression. In v1 it is not a list of supported platforms and does not, by itself, guarantee that a particular sensor provides every required input.

polarizations

json
"NDPolI": {
    ...,
    "polarizations": [ 
        "VV", 
        "VH"
    ], 
    ...
}

An ordered, generated list of radar-polarization variables used by formula. The supported standards are HH, HV, VH, and VV. They are recorded in first-seen order and deduplicated, using the same extraction behavior as bands.

NDPolI therefore has polarizations equal to ["VV", "VH"] and an empty bands array. Indices with no radar inputs are serialized with an empty polarizations array ([]).

constants

json
"SAVI": {
    ...,
    "constants": { 
        "L": { 
            "default_value": 0.5, 
            "description": "Canopy background adjustment", 
            "suggested_range": [0.25, 1], 
            "suggested_values": { 
                "High vegetation densities": 0.25, 
                "Intermediate vegetation densities": 0.5, 
                "Low vegetation densities": 1.0
            } 
        } 
    }, 
    ...
}

An object mapping every registered constant used by formula to that index's definition. Each definition requires a string description and may include a numeric default_value. Integers and floating-point values are accepted; numeric strings and booleans are rejected. If no default is appropriate, the property is omitted rather than written as null.

Two further recommendation properties are optional:

PropertyTypeMeaning
suggested_valuesobjectConditions mapped to a numeric value or a two-number range
suggested_rangetwo-number arrayGeneral recommended interval for the constant

The keys of suggested_values are free-form condition descriptions supplied by the contributor. Each value must be either one number or an array containing exactly two numbers. suggested_range must likewise contain exactly two numbers. These fields document recommendations from the scientific source; they do not override default_value automatically.

The property is conditionally required. A formula that uses constants cannot be submitted without constants, and every formula constant must have exactly one definition. Missing constants, extra constants, and band names incorrectly placed in this object all fail validation. An index whose formula uses no constants may omit the constants property and is serialized with an empty object ({}).

Defaults are index-specific starting points rather than fixed mathematical requirements. Consumers may override them when an implementation or data source requires another value. Parameters such as lambdaN and lambdaR can omit default_value when the appropriate wavelength depends on the sensor.

The generated constants.json transposes these definitions for discovery. Its top-level keys are the standard constants, and each value maps catalogue keys to their submitted definition:

json
"L": {
    "SAVI": {
        "default_value": 0.5,
        "description": "Canopy background adjustment",
        "suggested_range": [0.25, 1],
        "suggested_values": {
            "High vegetation densities": 0.25,
            "Intermediate vegetation densities": 0.5,
            "Low vegetation densities": 1.0
        }
    },
    "SAVIT": {
        "default_value": 1.0,
        "description": "Canopy background adjustment"
    }
}

The old short_name metadata is not included. A registered constant with no current users is retained as an empty object so the file continues to expose the complete standard registry.

external_variables

json
"NIRvP": {
    ...,
    "external_variables": { 
        "PAR": { 
            "description": "Photosynthetically Active Radiation"
        } 
    }, 
    ...
}

An object mapping every registered external input used by formula to its index-specific definition. Each definition contains exactly one required property, description, whose value must be a string. Constant-oriented properties such as default_value, suggested_values, and suggested_range are rejected, as are any other unknown properties.

The property is conditionally required. A formula using an external variable cannot be submitted without its definition, and definitions not used by the formula are rejected. Indices without external inputs may omit the property in source code and are serialized with an empty object ({}).

NIRvP currently uses PAR, or photosynthetically active radiation. The catalogue describes the required external input but does not assign a default value or specify how it must be measured, resampled, or aligned with the spectral inputs.

The generated external_variables.json transposes these definitions in the same way as constants.json: top-level keys are registered external-variable standards, and each value maps catalogue keys to their definitions.

json
"PAR": {
    "NIRvP": {
        "description": "Photosynthetically Active Radiation"
    }
}

A registered external variable with no current users is retained as an empty object, so the file exposes the complete External registry.

contributor

json
"SAVI": {
    ...,
    "contributor": "https://github.com/davemlz", 
    ...
}

Identifies the person who contributed the catalogue entry. The current validator accepts either a GitHub profile URL or an email address. A GitHub profile is preferred in most existing entries because it provides a durable, public attribution link.

This property identifies the catalogue contributor, who is not necessarily an author of the scientific publication referenced by the index.

date_of_addition

json
"SAVI": {
    ...,
    "date_of_addition": "2021-04-07", 
    ...
}

The calendar date on which the index was added to Awesome Spectral Indices. It is validated as a real date and serialized in ISO 8601 date form: YYYY-MM-DD.

This is catalogue provenance metadata. It is not the publication date of the index, the acquisition date of an image, or the release date of the catalogue.

formula

json
"SAVI": {
    ...,
    "formula": "(1.0 + L) * (N - R) / (N + R + L)", 
    ...
}

The mathematical expression used to calculate the index. Variable names are case-sensitive and correspond to entries later written to bands, polarizations, constants, or external_variables.

Formulas use a deliberately small expression language. The current validator allows:

  • addition, subtraction, multiplication, division, and exponentiation;
  • unary positive and negative values;
  • integer and floating-point numeric literals;
  • supported variable names;
  • calls to the explicitly allowed min() and max() functions;
  • calls to the explicitly allowed unary tanh() function;
  • calls to the explicitly allowed two-input kernel() function; and
  • calls to the contextual spatial_max(), spatial_min(), and spatial_mean() reduction functions.

Attribute access, indexing, keyword arguments, arbitrary function calls, strings, booleans, and other Python syntax are rejected. The expression is parsed and inspected without being evaluated. Every variable must be registered in the catalogue's supported-variable enumeration before an index can be generated.

Functions in formulas: WCI3

WCI3 is the first catalogue entry that exercises nested allowed functions in a formula:

json
"WCI3": {
    ...,
    "bands": ["B", "R", "G", "RE1", "N"],
    "constants": {
        "epsilon": {
            "default_value": 1e-10,
            "description": "Adjustment constant for numerical stability"
        }
    },
    "formula": "((B - R)/(B + R + epsilon)) * tanh(R - max(B, G, RE1, N))",
    ...
}

Here, max(B, G, RE1, N) selects the greatest of four spectral inputs and the unary tanh() call transforms the resulting difference. The parser visits the arguments recursively, so the function names themselves do not appear in generated metadata: the five spectral variables become bands, while epsilon is validated and serialized under constants.

Function calls remain deliberately constrained. min() and max() accept positional arguments, tanh() accepts exactly one positional argument, and keywords, qualified calls such as math.tanh(), and arbitrary functions are rejected.

Function-call syntax is a v1 formula-language feature and is not part of the v0 catalogue schema. V1 formally introduces min(), max(), and tanh(), with WCI3 as the first catalogue entry to use them. WCI3 is therefore a v1-only index and cannot be added unchanged to the v0 catalogue.

Kernel evaluations: kNDVI

kNDVI shows how v1 represents kernel evaluations without introducing derived kernel operands:

json
"kNDVI": {
    ...,
    "bands": ["N", "R"],
    "classification": {
        "application_domain": "vegetation",
        "family": ["kernel"],
        "sensing_modalities": ["multispectral"]
    },
    "formula": "(kernel(N, N) - kernel(N, R)) / (kernel(N, N) + kernel(N, R))",
    ...
}

The correspondence with the previous notation is direct:

Previous operandV1 expression
kNNkernel(N, N)
kNRkernel(N, R)

kernel() requires exactly two positional expressions and accepts no keyword arguments. Its arguments are visited recursively by the formula parser, so function names and evaluated kernel results never enter the operand registry. Repeated inputs are deduplicated in generated band metadata, which is why the four calls in kNDVI still produce only ["N", "R"].

The migrated kEVI formula also makes a previously implicit dependency explicit: kNL becomes kernel(N, L). Consequently, kEVI now lists N, R, and B as bands and defines L as its canopy-background constant alongside g, C1, and C2.

At this stage, kernel() represents the kernel evaluation required by the index formula and classification.family identifies the index as kernel. The catalogue does not yet prescribe a specific kernel function or its runtime implementation. Consumers must use a compatible kernel definition when evaluating these indices.

Contextual reduction functions: CWI

CWI is the first catalogue entry to require values reduced across a spatial context:

json
"CWI": {
    ...,
    "bands": ["S2", "B"],
    "formula": "(spatial_max(S2) * B) / (spatial_max(B) * S2)",
    "reductions": {
        "space": {
            "scope": "aoi"
        }
    },
    ...
}

Both spatial_max() calls calculate one scalar maximum across all valid pixels in the supplied area of interest. Those scalars are broadcast when the remaining formula is evaluated per pixel. This differs from max(B, G, RE1, N), which compares several inputs at each individual pixel.

The three initial contextual functions are:

FunctionResult
spatial_max(X)Maximum valid value of X within the configured spatial scope
spatial_min(X)Minimum valid value of X within the configured spatial scope
spatial_mean(X)Arithmetic mean of the valid values of X within the configured spatial scope

Each function requires exactly one positional expression and does not accept keyword arguments. Its input variables are still extracted normally: CWI therefore generates bands as ["S2", "B"], without adding the function names or synthetic reduction results to the operand metadata.

The formula string preserves the published implementation of the index. Consumers are responsible for supplying the variables with compatible units, scaling, and preprocessing.

reductions

json
"CWI": {
    ...,
    "reductions": { 
        "space": { 
            "scope": "aoi"
        } 
    }, 
    ...
}

An object describing the execution context shared by contextual reductions in the formula. The formula identifies the reducer and dimension: for example, spatial_mean() identifies a mean over space. reductions.space.scope then identifies which spatial extent supplies the values.

The two currently supported spatial scopes are:

ScopeMeaning
aoiAll valid pixels within the area of interest supplied for evaluation
sceneAll valid pixels within the complete input scene supplied for evaluation

The property is conditionally required and validated in both directions. An index using any spatial_*() function must provide reductions.space, while an index with no spatial reduction cannot provide an unused space definition. Every spatial reduction in one formula currently shares the same scope. Indices without contextual reductions may omit reductions in their source definition and are serialized with an empty object ({}).

reductions configures operations already present in the formula; it does not declare additional operands or repeat each function call. No separate reductions.json file is generated. Implementations must evaluate the reduction over the configured context before broadcasting its scalar result through the pixelwise portion of the formula.

name

json
"SAVI": {
    ...,
    "name": "Soil-Adjusted Vegetation Index", 
    ...
}

The human-readable name of the spectral index. It is intended for documentation, search results, tables, and interfaces where the acronym alone would be ambiguous.

The current schema requires a string but does not impose a naming convention or require the value to be unique. Multiple indices may therefore have the same name, including indices used in different application domains.

source

json
"SAVI": {
    ...,
    "source": { 
        "source_companions": [], 
        "source_link": "https://doi.org/10.1016/0034-4257(88)90106-X", 
        "source_link_status": "operational", 
        "source_link_type": "doi", 
        "source_type": "article"
    }, 
    ...
}

The structured scientific source used to support the index definition. It preserves the link previously stored in reference, records optional publication-type metadata from the contributor, and adds generated information about the link itself.

The object has five properties:

PropertyRequired from contributorGeneratedAllowed values
source_companionsNoYesArray of catalogue keys
source_linkYesNoHTTP or HTTPS URL
source_link_statusNoYesoperational, down
source_link_typeNoYesdoi, other
source_typeNoNoSee the allowed values below
source_companions

A generated list of the case-sensitive catalogue keys of every other index whose source_link is exactly the same. The current index is never included in its own list, duplicate keys are not produced, and an index with a unique source link receives an empty list ([]).

For example, NDVI and TVI are part of the same source. NDVI therefore has the following generated value:

json
"source_companions": ["TVI"]

This property describes shared catalogue provenance. It does not imply that the companion indices use the same formula, bands, constants, application domain, or interpretation. Generated VitePress pages link each companion key to its corresponding index page.

The original source URL supplied by the contributor. It normally points to a DOI resolver or another stable page containing the publication in which the formula is described. It is required and must be an HTTP or HTTPS URL.

This is the v1 location of the value previously stored directly in reference. The link provides provenance for reviewing the formula and its intended use; it does not by itself establish scientific validity.

A generated snapshot of whether source_link can be reached. operational means the generator received a successful response or a response showing that the resource exists but restricts automated access. down means the link returned a not-found, gone, or server-error response, or remained unreachable after repeated attempts.

The generator checks each unique URL once per run and shares the result among indices that use the same source. The value can change between catalogue generations as websites become available or unavailable. It reports link availability only; it does not assess the content or scientific quality of the source.

A generated classification of the URL. It is doi when the link uses the doi.org or dx.doi.org resolver and other for every other valid HTTP or HTTPS source. This property describes the submitted link form, not whether a publication reachable through another website also has a DOI.

source_type

An optional contributor-provided classification of the scientific source. If provided, it must be exactly one of:

  • article
  • book
  • book_chapter
  • conference_paper
  • poster
  • report
  • preprint

The property is serialized as null when it has not yet been classified. SAVI is currently classified as an article, while NDVI and TVI are classified as conference_paper sources.

Unknown source properties and unsupported source_type values are rejected during validation. Contributors do not provide source_companions, source_link_status, or source_link_type; those fields are derived during generation.

acronym

json
"SAVI": {
    ...,
    "acronym": "SAVI", 
    ...
}

The concise abbreviation commonly used for the index in publications, code, and catalogue interfaces. It is case-sensitive and must not contain whitespace.

The current schema does not require acronyms to be unique and does not require acronym to equal the surrounding catalogue key. Multiple indices may share an acronym, including indices from different application domains. Consumers should therefore use the outer catalogue key when they need the exact key under which an entry is stored, and use acronym as display metadata.

How the v1 files are generated

The current v1 generation process is:

  1. Source definitions are loaded into validated Pydantic models.
  2. Each formula is parsed and validated. Its variables are classified as bands, polarizations, constants, or external variables. Constants and external variables are checked against the definitions submitted with that index, and contextual reduction dimensions are checked against reductions.
  3. Sensing modalities are generated from the extracted band and polarization standards and added to classification.
  4. Each source link is classified as doi or other.
  5. Each unique source link is checked and marked operational or down.
  6. Indices are grouped by exact source link and receive the keys of every other index in that group as source_companions.
  7. The catalogue is serialized to JSON and flattened into the public CSV.
  8. Band metadata is written alongside the catalogue. Per-index constant and external-variable definitions are grouped by their respective standards in constants.json and external_variables.json.

Unlike v0, there is no platform-inference step between formula parsing and serialization. The generated JSON preserves the nested SpectralIndices mapping, while the CSV contains one row per index with these columns:

text
acronym, name, classification, formula, bands, polarizations, constants,
external_variables, reductions, source, contributor, date_of_addition

The CSV does not contain the outer catalogue key as a separate column, and its classification, bands, polarizations, constants, external_variables, reductions, and source values are textual representations of their nested data. Applications that need keyed records, native JSON arrays, or native JSON objects should use spectral-indices-dict.json.

More changes will be documented here

This page describes only what has already been implemented. As the v1 schema evolves, new properties, changed behavior, and migration guidance will be added to this page.

Released under the MIT License.