V3 Transition Guide

We have deprecated evalscripts version 1 (V1) and version 2 (V2) and are transitioning to version 3 (V3). V1 and V2 are currently still working, but at the end of the transition, they will not be available anymore. After the end of the transition phase, all remaining V1 and V2 data products and scripts will be converted to V3 by us. We encourage you to convert your scripts and data products as soon as possible, so you have time to notice any issues that might appear.

To ease the transition for you, we have prepared the conversion tools. This guide explains how to use them and contains all the information you will need to transition to V3 smoothly. It provides detailed instructions and examples for the use cases where automatic conversion to evalscript V3 is not possible. At the end, we provide a short overview of the structural differences between all the evalscript versions in case you are not sure which version of evalscript you currently use.

Evalscript, custom script and script are used as synonyms in this tutorial. By data products we refer to the preconfigured evalscripts, which are available to the user in the Configuration Utility. By OGC request we mean WMS, WMTS and WFS requests.

How To Convert Your Scripts?

In most cases, transition to V3 can be accomplished by simply converting the syntax of your old evalscript to evalscript V3. We prepared a converter to help you with this. You can use the converter through the Configuration Utility or by sending a request to the converter API.

However, OGC requests (i.e. WMS, WTS and WCS request) are processed slightly differently when using evalscripts V3 comparing to OGC requests using evalscritps V1 and V2. If you use parameters BGCOLOR, TRANSPARENT or the suffix depth of FORMAT parameter in your OGC requests, solely converting your evalscript to V3 using our converter is not sufficient. You will need to do manual changes to ensure that the results obtained from SH remain the same after the conversion. In the following chapters we are providing detailed step-by-step instructions for conversion to V3 in these use cases:

  • If you specify background color in your OGC requests (i.e. you use BGCOLOR parameter in your OGC requests), check use case 1.
  • If you request images with transparent background in your OGC requests (i.e. you use TRANSPARENT parameter in your OGC requests), check use case 2.
  • If you request 16bit or 32bit data, check use case 4 (16bit) and use case 5 (32bit) examples. In evalscript V3, sampleType is used to control bit depth of requested data.
  • If you use data products with simple evalscript and request 16bit or 32bit data you will need to set the custom script (instead of data product) for your layer. Check use case 6.
  • If you use data products note that you will get an additional dataMask band after swapping to suggested V3 product. If this is problematic for your use case, you will need to set the custom script (instead of data product) for your layer. Check use case 7.

Note: These use cases are not mutually exclusive, more of them can apply for your request.

General notes

  • To test the conversion before using it in production, we suggest that you duplicate the layer first, then convert the evalscript in the duplicated layer and compare the results you get using both (old and V3) layers.

  • In case you are requesting UINT16 data with OGC services, the values obtained from SH can slightly differ after the transition to V3. This is because we now use values with double precision for processing. This effect shall not exceed value of 1 per pixel. During our tests, we noticed this effect for a bit less than 0.2% pixels.

  • In the vast majority of cases there is no need to change existing URLs of OGC requests, only evalscripts need to be adjusted. But if you use the same layer in various OGC requests with different settings for BGCOLOR, TRANSPARENCY, and depth, you will need to duplicate the layer for each of the OGC requests. Each of these layers will then need to be converted to V3 and the value of LAYERS parameter in your OGC request URL will need to be adjusted.

  • If you use your layer for FIS requests, you will need to ensure that sampleType: "FLOAT32" or sampleType: "AUTO" is used after the conversion to V3. Related to the previous item, if you e.g. use the same layer in WMS requests with FORMAT=image/tiff;depth=16 and in FIS request, you will need to duplicate the layer and then adjust custom scripts for each of them accordingly.

  • Note that default settings for parameters in OGC were: BGCOLOR=#FFFFFF (white color), TRANSPARENCY=False, FORMAT=image/tiff;depth=16. In evalscripts V3 the defualt value of sampleType parameter is AUTO. dataMask is not returned by default; when used for setting a background color, its default value is 0, which results in black color.

  • Simple scripts will not be deprecated. However, they are now versioned, so a tag //VERSION=3 can be added at the beginning. By using this tag you ensure that your script will always (even if we introduce evalscript V4 in the future) be processed with our V3 processing pipeline. Simple scripts without the tag will be processed with the latest processing pipeline (which is currently V3).

  • For Python users who use our sentinelhub-py package to download the data, we recommend:

    • Check which MimeType you use as image_format in your python code and then convert your scripts following the corresponding use case below. This is how MimeType types map to the values of FORMAT parameter:
      • TIFF => tiff
      • TIFF_d8 => tiff;depth=8
      • TIFF_d16 => tiff;depth=16
      • TIFF_d32f => tiff;depth=32f
    • If you created the configuration from Python template, you might need to switch to using custom scripts instead of products for layers NDVI and NDWI. See use case 6 and use case 7.
  • Here's how V1 and V2 mosaicking relate to V3 mosaicking:

temporal in
OGC query parameter or evalscript
V1/V2 mosaickingV3 mosaicking
false (default)N/ASIMPLE (default)
trueSCENE (default)ORBIT
trueTILETILE

Note: OGC temporal query parameter works only with V1 and V2 scripts.

How to use the converter tool

Convert your script to V3 in the Configuration Utility

To convert your scripts to V3, you can use the convert option in the Configuration Utility. When your layer is using either a V1 or V2 script, the convert button will appear.

Convert button

After clicking the convert button, you will see your older version displayed on the left, and your script will be automatically converted to V3, which will display on the right, as you can see on the image below.

Converting1

If your script is multitemporal, turn the "temporal" switch at the top left of the converting page on.

Temporal button1

Click "Apply" to confirm the conversion. Do not forget to click "Save layer" once the conversion dialog closes.

Convert using Converter API

You can also convert your custom script by sending a request to the converter tool API.

To send the request using Postman:

  1. Create a new POST request
  2. In the URL field, add https://services.sentinel-hub.com/api/V1/process/convertscript, and specify the required datasetType (S2L1C, S2L2A, L8L1C, MODIS, DEM, S1GRD, S3OLCI, S3SLSTR, S5PL2 or CUSTOM). If your script is V1 and temporal, add temporal=true parameter to the request. Note that for V2, the converter finds out whether the script is temporal or not from the script itself, so the parameter temporal=true should not be provided. In V1 scripts, it's not possible to identify the temporal ones from the script itself, so we have to provide the temporal=true parameter for them. Be careful to turn temporal=true back on, when you're done converting V2 and want to convert temporal V1 again.
  1. Add the script you want to convert into the Body/raw window ( and not into params/evalscript).
  2. Run your request and the converted script will be displayed in the window below.

Convert to V3 data products

Converted data products with evalscripts V3 (i.e. V3 data products) were added to the system by us. All V3 data products are transparent (they return an additional dataMask band), since this is the most common way our users use data products. If this is not suitable for your use case (for example, if you are a Python user, getting additional band as a result of the SH request may cause problems in your further processing) we recommend you to set a custom script for the layer and adjust it to your needs (see Use Case 6).

You can convert to V3 data product in the Configuration Utility. When your layer is using V1 or V2 data product, the convert button will appear. Click it and the "Convert the product to version 3" dialog will open. The evalscripts of both products will be displayed:

Convert product

Confirm the conversion by clicking "Apply".

Once the layer uses V3 data product a revert button will appear allowing you to revert back to the V1 or V2 data product. If you revert, a convert button will appear, so you can convert to V3 again.

Reverting

Use Cases and Examples

Use Case 0: Converting evalscripts with the converter

Let's suppose you have an NDVI script in V1 and a false color composite script in V2 and convert them to V3.

Example of converting NDVI evalscript V1 -> V3

Before: evalscript V1
function evaluatePixel(samples) {
let ndvi = index(samples[0].B08, samples[0].B04)
if (ndvi<-0.2) return [0,0,0];
else if (ndvi<-0.1) return [1,0,0];
else if (ndvi<0) return [0.5,0.6,0,0];
else if (ndvi<0.1) return [0.4,0,0];
else if (ndvi<0.2) return [1,1,0.2];
else if (ndvi<0.3) return [0.8,0.8,0.2];
else if (ndvi<0.4) return [0.4,0.4,0];
else if (ndvi<0.5) return [0.2,1,1];
else if (ndvi<0.6) return [0.2,0.8,0.8];
else if (ndvi<0.7) return [0,0.4,0.4];
else if (ndvi<0.8) return [0.2,1,0.2];
else if (ndvi<0.9) return [0.2,0.8,0.2];
else return [0,0.4,0];
}
function setup(ds) {
setInputComponents([ds.B04, ds.B08]);
setOutputComponentCount(3);
}
After: evalscript V3
//VERSION=3
function evaluatePixel(samples) {
let ndvi = index(samples.B08, samples.B04)
if (ndvi<-0.2) return [0,0,0];
else if (ndvi<-0.1) return [1,0,0];
else if (ndvi<0) return [0.5,0.6,0,0];
else if (ndvi<0.1) return [0.4,0,0];
else if (ndvi<0.2) return [1,1,0.2];
else if (ndvi<0.3) return [0.8,0.8,0.2];
else if (ndvi<0.4) return [0.4,0.4,0];
else if (ndvi<0.5) return [0.2,1,1];
else if (ndvi<0.6) return [0.2,0.8,0.8];
else if (ndvi<0.7) return [0,0.4,0.4];
else if (ndvi<0.8) return [0.2,1,0.2];
else if (ndvi<0.9) return [0.2,0.8,0.2];
else return [0,0.4,0];
}
function setup() {
return {
input: [{
bands: [
"B04",
"B08"
]
}],
output: { bands: 3 } }
}

Example of converting False color evalscript V2 -> V3

Before: evalscript V2
//VERSION=2
function evaluatePixel(samples) {
return {
default: [samples[0].B08, samples[0].B04, samples[0].B03]
}
}
function setup(ds) {
return {
components: [ds.B08, ds.B04, ds.B03],
output: [
{
id: "default",
sampleType: SampleType.AUTO,
componentCount: 3
}
]
}
}
After: evalscript V3
//VERSION=3
function evaluatePixel(samples) {
return [samples.B08, samples.B04, samples.B03]
}
function setup() {
return {
input: [{
bands: [
"B08",
"B04",
"B03"
]
}],
output: { bands: 3 } }
}

Use Case 1: Background color

If you use BGCOLOR in your OGC requests you need to do the following: 1 – convert your evalscript to V3 with our converter (this step is optional if you use a simple script) 2 – add dataMask to the evalscript and use it to assign the background color to the no data pixels. See the examples here.

Example

WMS Request

https://services.sentinel-hub.com/ogc/wms/<instance_id>?version=1.1.1&service=WMS&request=GetMap&crs=EPSG%3A3857&layers=AGRICULTURE&bbox=313086.06785608194%2C939258.2035682461%2C469629.101784123%2C1095801.2374962876&time=2019-11-07/2019-11-07&width=512&height=512&format=image%2Fjpeg&transparent=false&bgcolor=0x643c28&

Before: evalscript V1
function evaluatePixel(samples) {
return [samples[0].B11, samples[0].B08, samples[0].B02];
}
function setup(ds) {
setInputComponents([ds.B11, ds.B08, ds.B02]);
setOutputComponentCount(3);
}
After: evalscript V3
//VERSION=3 (auto-converted from 1) + using dataMask to specify bgcolor
function evaluatePixel(samples) {
if (samples.dataMask == 1){
return [samples.B11, samples.B08, samples.B02];
} else {
return [100/255, 60/255, 40/255]
}
}
function setup() {
return {
input: [{
bands: [
"B11",
"B08",
"B02",
"dataMask"
]
}],
output: {
bands: 3
}
}
}

Use Case 2: Transparency (and png format)

If you use TRANSPARENT=TRUE in your OGC requests and you are using either a V1 or V2 script, you need to do the following: 1 – convert your evalscript to V3 with our converter 2 – add dataMask to the evalscript and return it as an additional band 3 - increase the number of output bands in function setup() -> output -> bands

If you use TRANSPARENT=TRUE in your OGC requests and you are using a simple script add dataMask to the returned array. See the example here.

Example

WMS Request

https://services.sentinel-hub.com/ogc/wms/<instance_id>?version=1.1.1&service=WMS&request=GetMap&format=image%2Fpng&crs=EPSG%3A3857&layers=AGRICULTURE&bbox=313086.06785608194%2C939258.2035682461%2C469629.101784123%2C1095801.2374962876&time=2019-11-07/2019-11-07&width=512&height=512&transparent=true

Before: evalscript V1
function evaluatePixel(samples) {
return [samples[0].B11, samples[0].B08, samples[0].B02];
}
function setup(ds) {
setInputComponents([ds.B11, ds.B08, ds.B02]);
setOutputComponentCount(3);
}
After: evalscript V3
//VERSION=3 (auto-converted from 1) + adding dataMask for transparency
function evaluatePixel(samples) {
return [samples.B11, samples.B08, samples.B02, samples.dataMask];
}
function setup() {
return {
input: [{
bands: [
"B11",
"B08",
"B02",
"dataMask"
]
}],
output: {
bands: 4
}
}
}

Use Case 3: FORMAT=image/tiff;depth=8

If you use FORMAT=image/tiff;depth=8 in your OGC requests you need to do the following: 1 – convert your evalscript to V3 with our converter If you need to ensure that the no-data pixel values stay as they were, do also: 2 – add dataMask to the evalscript and use it to assign white color to the no data pixels

Note: Since SampleType is not specified in evalscript V3 the default value AUTO will be used.

Example

WMS Request

https://services.sentinel-hub.com/ogc/wms/<instance_id>?version=1.1.1&service=WMS&request=GetMap&format=image%2Ftiff;depth=8&crs=EPSG%3A3857&layers=AGRICULTURE&bbox=313086.06785608194%2C939258.2035682461%2C469629.101784123%2C1095801.2374962876&time=2019-11-07/2019-11-07&width=512&height=512

Before: evalscript V1
function evaluatePixel(samples) {
return [samples[0].B11, samples[0].B08, samples[0].B02];
}
function setup(ds) {
setInputComponents([ds.B11, ds.B08, ds.B02]);
setOutputComponentCount(3);
}
After: evalscript V3
//VERSION=3
function evaluatePixel(samples) {
if (samples.dataMask==0)return [255, 255, 255]
return [samples.B11, samples.B08, samples.B02];
}
function setup() {
return {
input: [{
bands: [
"B11",
"B08",
"B02",
"dataMask"
]
}],
output: {
bands: 3
}
}
}

Use Case 4: FORMAT=image/tiff;depth=16 or FORMAT is not specified

If you use FORMAT=image/tiff;depth=16 or FORMAT=image/tiff in your OGC requests or if FORMAT parameter is not specified, you need to do the following: 1 – Convert your evalscript to V3 with our converter. In case you use simple evalscript, you will have to re-write it to a non-simple one, since simple evalscripts do not support sampleType parameter. 2 - add sampleType: "UINT16" to the setup () function -> output. 3 - scale the values to use the whole UINT16 range. If you need to ensure that the no-data pixels values stay as they were, do also: 4 – add dataMask to the evalscript and use it to assign white color to the no data pixels

Note: In the example below the input values are representing S2 reflectance from the interval [0,1], thus we scale with factor 65535. This will ensure that the results you get from SH will remain the same after the conversion, because scaling with 65535 was done on SH side for V1 and V2 evalscripts. However, if you do not need to ensure this backwards compatibility, some other scaling factors might be better for your use case.

Example

WMS Request

https://services.sentinel-hub.com/ogc/wms/<instance_id>?version=1.1.1&service=WMS&request=GetMap&format=image%2Ftiff&crs=EPSG%3A3857&layers=AGRICULTURE&bbox=313086.06785608194%2C939258.2035682461%2C469629.101784123%2C1095801.2374962876&time=2019-11-07/2019-11-07&width=512&height=512&transparent=false

Before: evalscript V1
function evaluatePixel(samples) {
return [samples[0].B11, samples[0].B08, samples[0].B02];
}
function setup(ds) {
setInputComponents([ds.B11, ds.B08, ds.B02]);
setOutputComponentCount(3);
}
After: evalscript V3
//VERSION=3 (auto-converted from 1) + dataMask to control background color + scaling to UINT16 range
function evaluatePixel(samples) {
var factor = 65535
if (samples.dataMask == 0) return [65535, 65535, 65535]
return [samples.B11*factor, samples.B08*factor, samples.B02*factor];
}
function setup() {
return {
input: [{
bands: [
"B11",
"B08",
"B02",
"dataMask"
]
}],
output: {
bands: 3,
sampleType:"UINT16"
}
}
}

Use Case 5: FORMAT=image/tiff;depth=32F

If you use FORMAT=image/tiff;depth=32F in your OGC requests, you need to do the following: 1 – Convert your evalscript to V3 with our converter. In case you use simple evalscript, you will have to re-write it to a non-simple one, as simple evalscripts do not support sampleType parameter. 2 - add sampleType: »FLOAT32« to the setup () function -> output -> sampleType. If you need to ensure that also the values for no data pixels stay exactly as they were, do: 3 – add dataMask to the evalscript and use it to assign white color to the no data pixels.

Note: Requesting depth=32F is commonly used by our Python users who specify this by image_format=MimeType.TIFF_d32f.

Example

WMS Request

https://services.sentinel-hub.com/ogc/wms/<instance_id>?version=1.1.1&service=WMS&request=GetMap&format=image%2Ftiff;depth=32f&crs=EPSG%3A3857&layers=AGRICULTURE&bbox=313086.06785608194%2C939258.2035682461%2C469629.101784123%2C1095801.2374962876&time=2019-11-07/2019-11-07&width=512&height=512

Before: evalscript V1
function evaluatePixel(samples) {
return [samples[0].B11, samples[0].B08, samples[0].B02];
}
function setup(ds) {
setInputComponents([ds.B11, ds.B08, ds.B02]);
setOutputComponentCount(3);
}
After: evalscript V3
//VERSION=3 (auto-converted from 1) + adding SampleType
function evaluatePixel(samples) {
if (samples.dataMask==0) return[1, 1, 1]
return [samples.B11, samples.B08, samples.B02];
}
function setup() {
return {
input: [{
bands: [
"B11",
"B08",
"B02",
"dataMask"
]
}],
output: {
bands: 3,
sampleType: "FLOAT32"
}
}
}

Use Case 6: Data product and FORMAT=image/tiff;depth=32F or FORMAT=image/tiff;depth=16

If you are using a data product and FORMAT=image/tiff;depth=32F or FORMAT=image/tiff;depth=16 in your OGC requests, you will need to switch from using a data product to using a custom script, because our V3 data products use sampleType: "AUTO". Do the following: 1 - Open the layer and click the "Edit" icon close to the custom script. 2 - Click "Copy script to editor" and then "Set custom script". Click "Save layer". The layer now uses V1 or V2 evalscript instead of the product. To convert it to V3 now follow the instructions for the Use case 4 if you use FORMAT=image/tiff;depth=16 or for the Use case 5 if you use FORMAT=image/tiff;depth=32F.

Example

WMS request

https://services.sentinel-hub.com/ogc/wms/<instance_id>?version=1.1.1&service=WMS&request=GetMap&crs=EPSG%3A3857&layers=DEM___RAW&format=image%2Ftiff;depth=32f&bbox=313086.06785608194%2C939258.2035682461%2C469629.101784123%2C1095801.2374962876&time=2019-11-07/2019-11-07&width=512&height=512

Before: simple evalscript
return [DEM]
After: evalscript V3
//VERSION=3
function evaluatePixel(samples) {
return [samples.DEM];
}
function setup() {
return {
input: [{
bands: [
"DEM"
]
}],
output: {
bands: 1,
sampleType: "FLOAT32"
}
}
}

Use Case 7: Use custom script V3 instead of transparent V3 data product

If you use data product and the corresponding transparent V3 data product does not meet your needs, you will have to switch to using a custom script. To do so:

  • Convert to V3 product and save a layer
  • Click on the edit icon close to the custom script to open Custom script editing dialog
  • Now use "Copy custom script to the editor" option. This will copy the evalscript to the text field on your right.
  • Remove dataMask from the script and reduce the number of output bands for 1.
  • Save the layer.

Differences Between Versions

Simple scripts

Simple scripts require no functions; bands can be called and manipulated in a simple manner. The following example will return a true color image.

return[2.5 * B04, 2.5 * B03, 2.5 * B02]

Non-simple scripts

Non-simple scripts require setup() and evaluatePixel() functions to be set up. In setup(), we specify the input bands and the number of output bands; 1 usually used for FIS, metadata or grayscale visualizations, 3 usually used for RGB outputs and 4 usually used for RGB + transparency. In function evaluatePixel(), we specify the output result of the request (e.g. a visualization). We also have to specify which samples we want - for example, samples.B04 will return pixel values of the band 4. V1 and V2 scripts also require the specific acquisition to be set (samples[0].B04 would return pixel values for the first available acquisition of band 4). Which acquisition is chosen as "first available", depends on mosaicking order and type. In V3, the latter is not required, unless MOSAICKING parameter is set.

The following examples all return Sentinel-2 true color results.

V1 scripts

In V1 setup() function, we specify setInputComponents(), where the input components (bands) are set, and setOutputComponentCount() we set the number of output bands.

function evaluatePixel(samples) {
return [samples[0].B04, samples[0].B03, samples[0].B02];
}
function setup(ds) {
setInputComponents([ds.B04, ds.B03, ds.B02]);
setOutputComponentCount(3);
}

V2 scripts

In V2, //VERSION=2 needs to be set at the beginning, so that the script recognizes the version. The structure of the script is similar to V1, but a bit different. Instead of setInputComponents(), we now have components and instead of setOutputComponentCount() we now have output, where we specify componentCount.

//VERSION=2
function evaluatePixel(samples) {
return {
default: [samples[0].B04, samples[0].B03, samples[0].B02]
}
}
function setup(ds) {
return {
components: [ds.B04, ds.B03, ds.B02],
output: [
{
id: "default",
sampleType: SampleType.AUTO,
componentCount: 3
}
]
}
}

V3 scripts

In V3, //VERSION=3 needs to be set at the beginning, so that the script recognizes the version. The structure of the script is similar to V2, but instead of components, we now have input, which includes the specified bands and output, where we specify the number of bands. V3 scripts are much more powerful than the previous versions. V1 and V2 supported multitemporal scripting but did not have support for dataMask or data fusion for example. V3 evalscript is documented very well on our documentation. You can find detailed explanations and examples there.

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