Evalscript V3

Start your evalscript with //VERSION=3 so the system will interpret it as such.

For evalscript V3 you need to specify two functions (described in detail below):

  • setup - where you specify inputs and outputs.
  • evaluatePixel - which calculates the output values for each pixel.

This is an example of a simple V3 evalscript which returns a true color image:

//VERSION=3
function setup() {
return {
input: ["B02", "B03", "B04"],
output: { bands: 3 }
};
}
function evaluatePixel(sample) {
return [2.5 * sample.B04, 2.5 * sample.B03, 2.5 * sample.B02];
}

setup function

This function is required as it sets up the input and output settings.

Specifics

Setup needs to return a javascript object with the following properties:

Input object properties

  • bands - an array of strings representing band names
  • units (optional) - a string (all bands will use this unit) or an array of strings listing the units of each band. For a description of units see the documentation of the collection you are querying. Defaults to the default units for each band.
  • metadata (optional) - an array of strings representing properties which can be added to the metadata. Options:
  • "bounds" - specifying this will add dataGeomtery and dataEnvelope to tiles

Output object properties

  • id (optional) - any string of your choosing. Must be unique if multiple output objects are defined. Defaults to default.
  • bands - the number of bands in this output.
  • sampleType (optional) - sets the SampleType constant defining the returned raster sample type. Defaults to AUTO.
  • nodataValue (optional) - sets the GDAL nodata metadata tag to the specified value. Only applicable for tiff files.

Note that the number of bands represent the number of components in the output image. JPEG and PNG, for example, can only support 1 or 3 color components (plus an alpha channel for PNG, if set). The sampleType also needs to be compatible with the output raster format.

Mosaicking

Mosaicking defines how the source data is mosaicked. Not all collections support all these mosaicking types as it depends on how the source data is distributed. See the collection information pages to determine which ones are supported. It is a constant which is specified by a string. To use, for example, set: mosaicking: "SIMPLE".

  • SIMPLE (default) - the simplest method, it flattens the mosaicked image so only a single sample is passed to evaluation.
  • ORBIT - the mosaicked image is flattened for each orbit so that there is only one sample per pixel per orbit. Multiple samples can therefore be present if there is more than one orbit for the selected time range at the pixel location.
  • TILE - this is essentially the unflattened mosaic. It contains all data available for the selected time range. Multiple samples can be present as each sample comes from a single scene. What a scene is is defined by the datasource.

Note: ORBIT mosaicking currently does not work exactly as described but generates a single scene for each day containing satellite data. For most requests this should not be an issue, however high latitude regions may have more than one acquisition per day. For these consider using TILE mosaicking if getting all available data is paramount. This will be corrected in future releases.

SampleType

SampleType defines the sample type of the output raster. This needs to be compatible with the raster format (e.g. JPEG cannot be FLOAT32). It is a constant which is specified by a string. To use, for example, set: sampleType: "AUTO".

  • UINT8 - unsigned 8-bit integer (values should range from 0-255)
  • UINT16 - unsigned 16-bit integer (values should range from 0-65535)
  • FLOAT32 - 32-bit floating point
  • AUTO (default) - values should range from 0-1, which will then automatically be stretched from the interval [0, 1] to [0, 255] and written into an UINT8 raster. Values below 0 and above 1 will be clamped to 0 and 255, respectively. This is the default if sampleType is not set in the output object.

Note: Sentinel Hub currently only supports unsigned integer values, therefore requesting INT8 or INT16 will return the same as UINT8 or UINT16, respectively.

Handling SampleType in an Evalscript

It is the responsibility of the evalscript to return the values in the interval expected for the chosen sampleType. If no sampleType is specified, AUTO is selected and the evalscript should return values ranging from 0-1. If sampleType is UINT8, the evalscript should return values ranging from 0-255, and so on.

In case of input data provided as reflectance values ranging 0-1 (e.g., Sentinel and Landsat), no scaling is needed when AUTO or FLOAT32 sampleType are specified.

Examples

This simple Sentinel-2 setup() function gets bands B02, B03, B04 and returns (UINT16) 16 bit unsigned raster values.

function setup() {
return {
input: [{
bands: ["B02", "B03", "B04"], // this sets which bands to use
units: "DN" // here we optionally set the units. All bands will be in this unit (in this case Digital numbers)
}],
output: { // this defines the output image type
bands: 3, // the output of this evalscript will have RGB colors
sampleType: "UINT16" // raster format will be UINT16
}
};
}

This Sentinel-2 setup() function gets bands B02, B03, B04 and returns a single raster with 8-bit integer values. To return values in the correct interval for the UINT8 sampleType, the evaluatePixel() function multiplies the reflectance values by 255. A true color image is returned.

function setup() {
return {
input: [{
bands: ["B02", "B03", "B04"], // this sets which bands to use
}],
output: {
bands: 3,
sampleType: "UINT8" // raster format will be UINT8
}
};
}
function evaluatePixel(sample) {
return [sample.B04 * 255, sample.B03 * 255, sample.B02 * 255]; // bands need to be multiplied by 255
}

In case of UINT16, the multiplication factor in evaluatePixel() would be 65535 instead of 255.

The following example uses bands with different units and produces two rasters:

function setup() {
return {
input: [{
bands: ["B02", "B03", "B04", "B08"],
units: ["reflectance", "reflectance", "reflectance", "DN"] // B08 will be in digital numbers, the rest reflectance
}],
output: [{ // this is now an array since there are multiple output objects
id: "rgb"
bands: 3
}, {
id: "falseColor"
bands: 3
}]
}
}

evaluatePixel function

The evaluatePixel function is a mapping which maps the input bands in their input units to the values in the output raster(s). The function is executed once for each output pixel.

Parameters

The evaluatePixel function has five positional parameters:

function evaluatePixel(samples, scenes, inputMetadata, customData, outputMetadata)

The first two parameters can be objects or arrays depending on requested mosaicking as explained below. They are additionally changed for data fusion requests, which is documented separately here. The remaining parameters are always objects.

samples

  • When mosaicking is SIMPLE:
    • samples - an object containing the band values of the single mosaicked sample, in the specified units, as its properties. The property names equal the names of all the input bands, pixel values of a band can be accessed as e.g. samples.B02.

NOTE: When using mosaicking SIMPLE we usually call this parameter sample in our examples to emphasize that it is an object and not an array.

  • When mosaicking is TILE or ORBIT:
    • samples - an array of samples as defined in the SIMPLE case. None*, one or multiple samples can therefore be present depending on how many orbits/tiles there are for the selected time range and area of interest. Pixel values of a band can be accessed for each sample as an item of the array, e.g. samples[0].B02.

*NOTE: In case samples is an empty array, calling samples[0].B02 will raise an error and it is up to users to handle this in their evalscript.

scenes

  • When mosaicking is SIMPLE:

    • scenes object is empty.
  • When mosaicking is ORBIT:

    • scenes - an array of objects containing metadata for each orbit (day). The length of scenes array is the same as length of samples array. A value of metadata, for example dateFrom can be accessed as scenes.orbits[0].dateFrom. Each object's properties include:
      • dateFrom (string) - date and time, together with orbits.dateTo represents the time interval of one day. All tiles acquired on this day are mosaicked into this scene.
      • dateTo (string) - date and time, together with orbits.dateFrom represents the time interval of one day. All tiles acquired on this day are mosaicked into this scene.
      • tiles (array) - an array of metadata for each tile used for mosaicking of this orbit. Each element has the same properties as elements of scenes.tiles (listed just below for mosaicking TILE).
  • When mosaicking is TILE:

    • scenes - an array of objects containing metadata for each tile. The length of scenes array is the same as length of samples array. A value of metadata, for example cloudCoverage can be accessed as scenes.tiles[0].cloudCoverage. Each object's properties include:
      • date (string or js datetime) - A date when the tile was acquired.
      • shId (number) - Sentinel Hub internal identifier of the tile. For example 11583048.
      • cloudCoverage (number) - Estimated percentage of pixels covered by clouds in the tile. A value 2.09 means that 2.09% of pixels in the tile are cloudy.
      • dataPath (string) - Path to whee the tile is stored on a cloud. For example "s3://sentinel-s2-l2a/tiles/33/T/VM/2020/9/15/0".
      • dataGeometry (geojson - like object, see example) - an optional property, added only when requested. Represents a geometry of data coverage within the tile.
      • dataEnvelope (geojson - like object, see example) - an optional property, added only when requested. Represents a bbox of dataGeometry.

NOTE: Objects may contain also fields prefixed by __ (double underscore). Such fields are used internally by Sentinel Hub services. Evalscripts should not make use of them because they can be changed or removed at any time and must never modify or delete such fields. Doing so may cause your request to fail or return incorrect results.

inputMetadata

inputMetadata is an object containing metadata used for processing by Sentinel Hub. Its properties are:

  • serviceVersion - the version of Sentinel Hub which was used for processing.
  • normalizationFactor - the factor used by Sentinel Hub to convert digital numbers (DN) to reflectance using REFLECTANCE = DN * normalizationFactor. This is useful when requesting bands for which both units - DN and REFLECTANCE - are supported.

customData

customData is an object reserved for possible future use.

outputMetadata

outputMetadata is an object which can be used to output any user defined metadata including passing scenes objects, user defined thresholds or ids of original tiles used for processing. It contains:

  • userData - is a generic object and can contain any data. This can be pushed to the API response by adding a userdata identified output response object to your API request (see this for details or an example here).

Returns

The evaluatePixel function can return:

  • An object whose keys are the output ids and its values are arrays of numbers. The length of the array is bound by the output object bands number and the values by sampleType.
  • An array of numbers with the same rules as above. This option can be used only when a single image output is defined.
  • Nothing; the return statement is not specified. This is useful when only information in outputMetadata.userData is needed.

Input Units and Output Values

The values of each sample is the units specified in the input object. See the input object documentation for more information. How the output values are written to the output raster depends on the sample type. AUTO will stretch values in the interval [0, 1] to [0, 255] and then write those values into an UINT8 raster. The remaining sample types expect values within the range of the sample format.

Examples

Example evaluatePixel script returns a simple True Color image based on bands B04, B03, B02:

function evaluatePixel(sample) {
return [2.5 * sample.B04, 2.5 * sample.B03, 2.5 * sample.B02];
}

When we have multiple outputs in the setup function we can provide them as such:

function evaluatePixel(sample) {
return {
trueColor: [2.5 * sample.B04, 2.5 * sample.B03, 2.5 * sample.B02],
falseColor: [2.5 * sample.B08, 2.5 * sample.B04, 2.5 * sample.B03]
};
}

Calculate the average value of band B04 when using ORBIT or TILE mosaicking:

function evaluatePixel(samples) {
var sum = 0;
var nonZeroSamples = 0;
for (var i = 0; i < samples.length; i++) {
var value = samples[i].B04;
if (value != 0) {
sum += value;
nonZeroSamples++;
}
}
return [sum / nonZeroSamples];
}

updateOutputMetadata function (optional)

This function is optional and if present is called at the end of evalscript evaluation. It provides a convenient way to forward information pertaining to the returned data as a whole (as opposed to evaluatePixel which is run for each pixel) into an output object. Do this by setting the userData property of the outputMetadata parameter to any value you require.

Parameters

These are the full parameters of the updateOutputMetadata function:

function updateOutputMetadata(scenes, inputMetadata, outputMetadata)

See description of parameters in the "evaluatePixel function" chapter:

preProcessScenes function (optional)

NOTE: This function shall be used instead of filterScenes function.

This function is optional, and if present is called at the beginning of the script evaluation before the actual satellite data is processed. Use it when mosaicking is set to ORBIT or TILE. It provides additional filtering functionality for scenes, after the constraints set in the request parameters are already applied. This is useful, for example, to reduce the number of scenes needed, thereby reducing processing time and the number of processing units for the request.

Parameters

These are the full parameters of the preProcessScenes function:

function preProcessScenes(collections)

collections

collections is an object, which contains different properties depending on which mosaicking option is selected.

  • If mosaicking is ORBIT, collections contains:

    • from (type Date) - the value given as timeRange.from in the body of the request, representing the start of the search interval
    • to (type Date) - the value given as timeRange.to in the body of the request, representing the end of the search interval
    • scenes.orbits - corresponds to scenes.orbits as described for evalautePixel function and mosaicking ORBIT here but it doesn't contain tiles.
  • If mosaicking is TILE, collections contains:

    • scenes.tiles - corresponds to scenes.tiles as described for evalautePixel function and mosaicking TILE here.

Returns

The preProcessScenes function must return an objects of the same type as collections. Most often, a sub-set of the input collections will be returned, e.g. to keep only the data acquired before 1.2.2019:

function preProcessScenes(collections){
collections.scenes.orbits = collections.scenes.orbits.filter(function (scene) {
return new Date(scene.dateFrom) < new Date("2019-02-01T00:00:00Z")
});
return collections
}

Examples

Filter scenes by particular days

In this example, we use preProcessScenes function to select images acquired on two particular dates within the requested timeRange. This example was taken (and adopted) from the evalscript for delineation of burned areas, based on the comparison of Sentinel-2 images acquired before (i.e. on "2017-05-15") and after (i.e. on "2017-06-24") the event.

If mosaicking is ORBIT:
function preProcessScenes (collections) {
var allowedDates = ["2017-05-15", "2017-06-24"]; //before and after Knysna fires
collections.scenes.orbits = collections.scenes.orbits.filter(function (orbit) {
var orbitDateFrom = orbit.dateFrom.split("T")[0];
return allowedDates.includes(orbitDateFrom);
})
return collections
}
If mosaicking is TILE:
function preProcessScenes (collections) {
var allowedDates = ["2017-05-15", "2017-06-24"]; //before and after Knysna fires
collections.scenes.tiles = collections.scenes.tiles.filter(function (tile) {
var tileDate = tile.date.split("T")[0];
return allowedDates.includes(tileDate);
})
return collections
}

Filter scenes by time interval

Here, we filter out (= remove) all the scenes acquired between the two selected dates, which both fall within the requested time range.

If mosaicking is ORBIT:
function preProcessScenes (collections) {
collections.scenes.orbits = collections.scenes.orbits.filter(function (orbit) {
return (new Date(orbit.dateFrom) < new Date("2019-01-31T00:00:00Z")) ||
(new Date(orbit.dateFrom) >= new Date("2019-06-01T00:00:00Z"))
})
return collections
}
If mosaicking is TILE:
function preProcessScenes (collections) {
collections.scenes.tiles = collections.scenes.tiles.filter(function (tile) {
return (new Date(tile.date) < new Date("2019-01-31T00:00:00Z")) ||
(new Date(tile.date) >= new Date("2019-06-01T00:00:00Z"))
})
return collections
}

Specify the number of months taken into account

Values of timeRange.from and timeRange.to parameters as given in the request, are available in the preProcessScenes function as collections.to and collections.from, respectively. Mosaicking must be ORBIT to use these parameters. They can be used to e.g. filter out scenes acquired more than 3 months before the given to date and time.

function preProcessScenes (collections) {
collections.scenes.orbits = collections.scenes.orbits.filter(function (orbit) {
var orbitDateFrom = new Date(orbit.dateFrom)
return orbitDateFrom.getTime() >= (collections.to.getTime()-3*31*24*3600*1000);
})
return collections
}

The 3*31*24*3600*1000 represents the 3 months converted to milliseconds. This is needed, so that a 3-month time span can be compared to scene.dateFrom and collections.to, which are all returned as milliseconds since 1970-1-1 by the getTime() function. Note: The result is the same as if the timeRange.from parameter in the body of the request is set to 3 months prior to the timeRange.to.

Select one image per month

In this example, we filter the available scenes, so that only the first scene acquired in each month is sent to the evaluatePixel function:

If mosaicking is ORBIT:
function preProcessScenes (collections) {
collections.scenes.orbits.sort(function (s1, s2) {
var date1 = new Date(s1.dateFrom);
var date2 = new Date(s2.dateFrom);
return date1 - date2}) // sort the scenes by dateFrom in ascending order
firstOrbitDate = new Date(collections.scenes.orbits[0].dateFrom)
var previousOrbitMonth = firstOrbitDate.getMonth() - 1
collections.scenes.orbits = collections.scenes.orbits.filter(function (orbit) {
var currentOrbitDate = new Date(orbit.dateFrom)
if (currentOrbitDate.getMonth() != previousOrbitMonth){
previousOrbitMonth = currentOrbitDate.getMonth();
return true;
} else return false;
})
return collections
}
If mosaicking is TILE:
function preProcessScenes (collections) {
collections.scenes.tiles.sort(function (s1, s2) {
var date1 = new Date(s1.date);
var date2 = new Date(s2.date);
return date1 - date2}) // sort the scenes by dateFrom in ascending order
firstTileDate = new Date(collections.scenes.tiles[0].date)
var previousTileMonth = firstTileDate.getMonth() - 1
collections.scenes.tiles = collections.scenes.tiles.filter(function (scene) {
var currentTileDate = new Date(scene.date)
if (currentTileDate.getMonth() != previousTileMonth){
previousTileMonth = currentTileDate.getMonth();
return true;
} else return false;
})
return collections
}

filterScenes function (optional, deprecated)

NOTE: filterScenes function is now deprecated, as it does not work for data fusion requests. It still works (and will keep working) as documented below but we recommend using preProcessScenes function instead.

This function is optional, and if present is called at the beginning of the script evaluation before the actual satellite data is processed. Use it when mosaicking is set to ORBIT or TILE. It provides additional filtering functionality for scenes, after the constraints set in the request parameters are already applied. This is useful, for example, to reduce the number of scenes needed, thereby reducing processing time and the number of processing units for the request.

Parameters

These are the full parameters of the filterScenes function:

function filterScenes(availableScenes, inputMetadata)
  • availableScenes - an array of objects where each of them represents one available scene for a given request. Each object has two properties:
    • date (type Date) -- the date and time of the scene
  • inputMetadata - an object with properties:
    • from (type Date) -- the value given as timeRange.from in the body of the request, representing the start of the search interval
    • to (type Date) -- the value given as timeRange.to in the body of the request, representing the end of the search interval
    • scenes -- the array equal to availableScenes

Returns

The filterScenes function must return an array of objects of the same type as contained in an availableScenes array. Most often, a sub-set of the availableScenes array will be returned:

function filterScenes(availableScenes, inputMetadata){
return availableScenes.filter(function (scene) {
return scene.date.getTime() < new Date("2019-02-01T00:00:00Z")
});
}

Examples

Filter scenes by particular days

In this example, we use filterScenes function to select images acquired on two particular dates within the requested timeRange. This example was taken (and adopted) from the evalscript for delineation of burned areas, based on the comparison of Sentinel-2 images acquired before (i.e. on "2017-05-15") and after (i.e. on "2017-06-24") the event.

function filterScenes (availableScenes, inputMetadata) {
var allowedDates = ["2017-05-15", "2017-06-24"]; //before and after Knysna fires
return availableScenes.filter(function (scene) {
var sceneDateStr = scene.date.toISOString().split("T")[0]; //converting date and time to string and rounding to day precision
return allowedDates.includes(sceneDateStr);
});
}

Filter scenes by time interval

Here, we filter out (= remove) all the scenes acquired between the two selected dates, which both fall within the requested time range.

function filterScenes(availableScenes, inputMetadata) {
return availableScenes.filter(function (scene) {
return (scene.date.getTime() < new Date("2019-01-31T00:00:00Z")) ||
(scene.date.getTime() >= new Date("2019-06-01T00:00:00Z"))
});
}

Combining this with the timeRange set in the body of the request as:

{
"from": "2019-01-01T00:00:00Z",
"to": "2019-06-30T23:59:59Z"
}

we end up only with scenes acquired in January and June 2019. In the evaluatePixel function, we could then e.g., calculate the average NDVI index for each of the months and compare them.

Specify the number of months taken into account

Values of timeRange.from and timeRange.to parameters as given in the request, are available in the filterScenes function as iputMetadata.to and inputMetadata.from, respectively. These can be used to e.g. filter out scenes acquired more than 3 months before the given to date and time:

function filterScenes (availableScenes, inputMetadata) {
return availableScenes.filter(function (scene) {
return scene.date.getTime()>=(inputMetadata.to.getTime()-3*31*24*3600*1000);
});
}

The 3*31*24*3600*1000 represents the 3 months converted to milliseconds. This is needed, so that a 3-month time span can be compared to scene.date and inputMetadata.to, which are all returned as milliseconds since 1970-1-1 by the getTime() function. Note: The result is the same as if the timeRange.from parameter in the body of the request is set to 3 months prior to the timeRange.to.

Select one image per month

In this example, we filter the available scenes, so that only the first scene acquired in each month is sent to the evaluatePixel function:

function filterScenes(availableScenes, inputMetadata){
availableScenes.sort((s1, s2) => s1.date - s2.date); // sort the scenes by dates in ascending order
previousSceneMonth = availableScenes[0].date.getMonth()-1
return availableScenes.filter(function (scene) {
if (scene.date.getMonth() != previousSceneMonth ){
previousSceneMonth=scene.date.getMonth();
return true;
} else return false;
});
}

OGC services specifics

There are some specifics when using evalscript V3 with WMS, WTS, WCS services:

  • These services return only the default output. Only one image can be returned with each request and it is not possible to request metadata in JSON format.
  • TRANSPARENCY and BGCOLOR parameters are ignored. You can use dataMask band in evalscript V3 to handle transparency, as described here.
  • Bit depth, which is given as the part of a FORMAT parameter (e.g. FORMAT=image/tiff;depth=8) is ignored. You can use sampleType in evalscript V3 to request the bit depth of your choice.