A repository of custom scripts that can be used with Sentinel-Hub services.

Normalized difference vegetation index time series

Show script or download it.

Evaluate and visualize

Note: The color shown in the timelapse is generated by the visualisation script, which is NOT the output of this script.

General description

This script aims to obtain a time series within a specific time period by a single request. Usually, the number of output bands is required to be set in the evalscript when making a request; however, in case users are interested in a time-series analysis, they would like to have all (or partial if a filtering step is needed) available acquisitions whose number is not always clear before making a request.

In this script we take NDVI as an example, but this can be easily changed to other data. To obtain the exact NDVI value in the centre of Rome from 1st of July 2022 to 11th of July 2022, updateOutput function is used to update the number of output bands without knowing beforehand how many there are, which allows users to create a multi-band tiff having data of selected acquisition dates in each band. Furthermore, updateOutputMetadata function is used in the script to generate a json file with a list of the NDVI dates used in the analysis, which would be really useful in a time-series analysis.

To make this script work, the responses parameter in the payload need to be set as following:

"reponses": [
        "identifier": "default",
        "format": {
            "type": "image/jpeg"
        "identifier": "userdata",
        "format": {
            "type": "application/json"

As an alternative, copy the curl command below to the Request Preview window of Requests Builder, the application can automatically generate the payload in JSON format or the Python code which is compatible with sentinelhub Python package.

curl -X POST  -H 'Content-Type: application/json' -H 'Authorization: Bearer eyJraWQiOiJzaCIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJjYjA0ZGNhMS1jOGYyLTQwMGUtODcxOS1lMjRmY2VkOThmZDYiLCJhdWQiOiIwZjYxZDM4NS01YzhiLTQ0ZjktYTE1NC0yYWRmNTFkNTAxNDEiLCJqdGkiOiIwN2YyYWJjNS04MjQyLTQwMmQtODRjYi1lYWIwYjYzZTBhNWIiLCJleHAiOjE2NTc1NTgwOTEsIm5hbWUiOiJDaHVuZy1YaWFuZyBIb25nIiwiZW1haWwiOiJjaHVuZy5ob3JuZ0BzaW5lcmdpc2UuY29tIiwiZ2l2ZW5fbmFtZSI6IkNodW5nLVhpYW5nIiwiZmFtaWx5X25hbWUiOiJIb25nIiwic2lkIjoiODYzODBiMmUtZTU4Ni00YjlhLThlMmMtYTQ1NGZjYjA0MzY5Iiwib3JnIjoiYTUyY2U2ZGEtMjI5MC00N2MyLTg0YjEtNWZkNTg5ZGFhYzI1IiwiZGlkIjoxLCJhaWQiOiJjNWU3OTA0OC1iYWYwLTQxMGItOGVhMS0zZGM5ZDgzZTBlYzgiLCJkIjp7IjEiOnsicmEiOnsicmFnIjo3fSwidCI6MTQwMDB9fX0.aZ4MXU_N0bsdg-2OctPAyrVrYOQVl9UimiEa6LvuXZNMRhRMFlxN5e_UxaVrZwH3kNwXSwE3guZrhtI8SOqleo8WJv4SsBQJuv_TrtzYEqL63CHVc7_j1sZjZWi0vUHqIr99sCvhn4ksBc9fW6lbQwiplBsen74-HiiMAJ_WaYe7MVrysoZ95oFM5cTuK8tkcIK9RTHJ4DvNVPy9OUV_CyUgxMVQdmoZBFukUu-fnhF8s_adUjKpDfIFOJQ8tC2GgOfaLcu5NzIjI0qysBao4oSLZYayVa2omyUezrS6ulpmvsUKtR16eRWqPIamyLLbcbZCvSs2URcmjXtSVcEpUA' -H 'Accept: application/tar'  -d '{  "input": {    "bounds": {      "bbox": [        12.44693,        41.870072,        12.541001,        41.917096      ]    },    "data": [      {        "dataFilter": {          "timeRange": {            "from": "2022-07-01T00:00:00Z",            "to": "2022-07-11T23:59:59Z"          }        },        "type": "sentinel-2-l2a"      }    ]  },  "output": {    "width": 779.8034286939699,    "height": 523.4687735062655,    "responses": [      {        "identifier": "default",        "format": {          "type": "image/tiff"        }      },      {        "identifier": "userdata",        "format": {          "type": "application/json"        }      }    ]  },  "evalscript": "//VERSION=3\n// Script to extract a time series of NDVI values using \n// Sentinel 2 Level 2A data and  metadata file.\nfunction setup() {\n    return {\n      input: [{\n        bands: [\"B04\", \"B08\"],\n        units: \"DN\"\n      }],\n      output: {\n        bands: 1,\n        sampleType: SampleType.FLOAT32\n      },\n      mosaicking: Mosaicking.ORBIT\n    }\n    \n  }\n  \n  // The following function is designed to update the number of\n  // output bands without knowing beforehand how many there are\n  function updateOutput(outputs, collection) {\n      Object.values(outputs).forEach((output) => {\n          output.bands = collection.scenes.length;\n      });\n  }\n  // function to generate a json file with a list of the NDVI \n  // dates used in the analysis. \n  function updateOutputMetadata(scenes, inputMetadata, outputMetadata) {\n      var dds = [];\n      for (i=0; i<scenes.length; i++){\n        dds.push(scenes[i].date)\n      }\n      outputMetadata.userData = { \"acquisition_dates\":  JSON.stringify(dds) }\n  }\n  \n  function evaluatePixel(samples) {\n    // Precompute an array to contain NDVI observations\n    var n_observations = samples.length;\n    let ndvi = new Array(n_observations).fill(0);\n    \n    // Fill the array with NDVI values\n    samples.forEach((sample, index) => {\n      ndvi[index] = (sample.B08 - sample.B04) / (sample.B08 + sample.B04) ;\n    });\n                       \n    return ndvi;\n  }"}'

Author of the script

William Ray

Description of representative images

The following GIF is the NDVI time series from 1st of July 2022 to 11th of July 2022 displayed in grayscale with QGIS.

NDVI time series example