Ndvi values are out of range of -1,1

using the following evalscript i obtain the ndvi values:

function setup() {
  return {
    input: [{
      bands: ["B04", "B08"],
      units: "DN"
    }],
    output: {
      bands: 1,
      sampleType: SampleType.FLOAT32
    },
    mosaicking: Mosaicking.ORBIT
  }
}
function evaluatePixel(samples) {
  // Precompute an array to contain NDVI observations
  var n_observations = samples.length;
  let ndvi = new Array(n_observations).fill(0);
  
  // Fill the array with NDVI values
  samples.forEach((sample, index) => {
    ndvi[index] = (sample.B08 - sample.B04) / (sample.B08 + sample.B04) ;
  });
                    
  return ndvi;
}

but the tiff file i receive contains the following data:

77,77,0,42,0,0,0,8,0,18,1,0,0,3,0,0,0,1,1,0,0,0,1,1,0,3,0,0,0,1,1,0,0,0,1,2,0,3,0,0,0,1,0,32,0,0,1,3,0,3,0,0,0,1,128,178,0,0,1,6,0,3,0,0,0,1,0,1,0,0,1,17,0,4,0,0,0,32,0,0,0,232,1,21,0,3,0,0,0,1,0,1,0,0,1,22,0,3,0,0,0,1,0,8,0,0,1,23,0,4,0,0,0,32,0,0,1,104,1,26,0,5,0,0,0,1,0,0,1,232,1,27,0,5,0,0,0,1,0,0,1,240,1,40,0,3,0,0,0,1,0,1,0,0,1,83,0,3,0,0,0,1,0,3,0,0,131,14,0,12,0,0,0,3,0,0,1,248,132,130,0,12,0,0,0,6,0,0,2,16,135,175,0,3,0,0,0,52,0,0,2,64,135,176,0,12,0,0,0,3,0,0,2,168,135,177,0,2,0,0,0,46,0,0,2,192,0,0,0,0,0,0,0,0,2,238,0,0,5,119,0,0,11,150,0,0,21,81,0,0,34,115,0,0,51,36,0,0,70,175,0,0,90,217,0,0,111,74,0,0,132,5,0,0,153,33,0,0,174,151,0,0,196,82,0,0,218,139,0,0,240,245,0,1,7,159,0,1,30,157,0,1,53,243,0,1,77,133,0,1,101,109,0,1,125,191,0,1,150,147,0,1,175,134,0,1,200,253,0,1,226,231,0,1,253,16,0,2,23,66,0,2,48,24,0,2,68,205,0,2,85,40,0,2,97,28,0,2,104,172,0,0,2,137,0,0,6,31,0,0,9,187,0,0,13,34,0,0,16,177,0

according to my understanding, the ndvi values should rang between -1,1

any explanation why i am getting these values?

I wasn’t able to reproduce your error. However you are returning an array of length greater than 1, but you only specify a single output band in the setup function. This will not work.

You can use updateOutput to actually return that many bands. See the docs: Evalscript V3

should i just modify the following json request to accommodate "default": { "bands": 2 }, "my_output": { "bands": 3 } as follows:

const req = {
	"input": {
		"bounds": {
		  "geometry": coordsInEPSG3857,
		  "properties": {
			"crs": "http://www.opengis.net/def/crs/EPSG/0/3857"
		  }
		},
		"data": [
		  {
			"dataFilter": {
			  "timeRange": {
				"from": sYear + "-" + sMonth + "-" + sDay + "T" + "00:00:00Z",
				"to": eYear + "-" + eMonth + "-" + eDay + "T" + "00:00:00Z"
			  }
			},
			"type": satMissionType
		  }
		]
	  },
	  "output": {
	  
		"default": {
			"bands": 2
		},
		"my_output": {
			"bands": 3
		},
		"responses": [
		  {
			"identifier": "default",
			"format": {
			  "type": "image/tiff"
			}
		}         
		]
	  },
	  "evalscript": evalscript,
	};

but how the evalscript should look like then please

No, the request body is not the place to specify number of returned bands. This has to be done in the evalscript.

What do you want to achieve with this evalscript?

Thanks for the reply
What I want to achieve is, to obtain ndvi values and they should range between -1,1
Please find the evaluation script I am using posted above in my question

And you want all NDVI values for a certain time period?

Yes please, for a certain time period. Where the time period is indicated in the request json. Is it clearer now?

Have you had a look at the documentation for updateOutput and especially the attached example? If so, please let me know what you’ve tried and where you are stuck.

See the link

Tomorrow I will study the link you provided, however, I would like to know why do I need to spelt the output band to be more than one?I just need ndvi, therefor, according to my understanding, I need one band as output. Am I right?

please find below my attempts to achieve the following:
i want to obtain ndvi values for a designated period of time, for instance, from:01-04-2024, to:30.04.2024 and the ndvi values’ range should be between -1, 1

evalscript:

`//VERSION=3
   function setup() {
	   return {
		   input: ["B04", "B08", "dataMask"],
		   
		   output: [{ 
			   id: "output_1",
			   bands: 1,
			   sampleType: "FLOAT32",
			   nodataValue: NaN
		   }]
	   };
	}

	function updateOutput(output, collection) {
	  output.output_1.bands = collection.scenes.length
  }
	
	function evaluatePixel(samples) {
	   if(!samples.dataMask){
		  return [NaN]
	   }
	   const ndvi = index(samples.B08, samples.B04);
	   return [ndvi]
	}`

json-request:

-d '{
  "input": {
	"bounds": {
	  "bbox": [
		12.44693,
		41.870072,
		12.541001,
		41.917096
	  ]
	},
	"data": [
	  {
		"dataFilter": {
		  "timeRange": {
			"from": "2024-04-01T00:00:00Z",
			"to": "2024-04-30T23:59:59Z"
		  }
		},
		"type": "sentinel-2-l2a"
	  }
	]
  },
  "output": {
	"width": 512,
	"height": 343.697,
	"responses": [
	  {
		"identifier": "default",
		"format": {
		  "type": "image/tiff"
		}
	  }
	]
  },
  "evalscript": "//VERSION=3\n\t   function setup() {\n\t\t   return {\n\t\t\t   input: [\"B04\", \"B08\", \"dataMask\"],\n\t\t\t   \n\t\t\t   output: [{ \n\t\t\t\t   id: \"output_1\",\n\t\t\t\t   bands: 1,\n\t\t\t\t   sampleType: \"FLOAT32\",\n\t\t\t\t   nodataValue: NaN\n\t\t\t   }]\n\t\t   };\n\t\t}\n\n\t\tfunction updateOutput(output, collection) {\n\t\t  output.output_1.bands = collection.scenes.length\n\t  }\n\t\t\n\t\tfunction evaluatePixel(samples) {\n\t\t   if(!samples.dataMask){\n\t\t\t  return [NaN]\n\t\t   }\n\t\t   const ndvi = index(samples.B08, samples.B04);\n\t\t   return [ndvi]\n\t\t}"
}'

Returning one band can only return a single value per pixel. Since you want to return all the NDVI values in a time frame per pixels you need more than one band.

Your evalscript seems to be almost there. Currently it does not return an array. Now you need to take the evaluate Pixel function which you had earlier, the one where you fill the array with NDVI values and apply it in your evalscript.

You also now return an output in the evalscript called output_1, but in your json request body, the identifier is default. This has to match up.

thanks,
now the json-request and the evalscript look as follows,but:

i do not know how to return more than one band! can you please help me in this regard?

json-request:

-d '{
  "input": {
	"bounds": {
	  "bbox": [
		12.44693,
		41.870072,
		12.541001,
		41.917096
	  ]
	},
	"data": [
	  {
		"dataFilter": {
		  "timeRange": {
			"from": "2024-04-01T00:00:00Z",
			"to": "2024-04-30T23:59:59Z"
		  }
		},
		"type": "sentinel-2-l2a"
	  }
	]
  },
  "output": {
	"width": 512,
	"height": 343.697,
	"responses": [
	  {
		"identifier": "output_1",
		"format": {
		  "type": "image/tiff"
		}
	  }
	]
  },
  "evalscript": "\n function setup() {\n   return {\n     input: [{\n       bands: [\"B04\", \"B08\"],\n       units: \"DN\"\n     }],\n     output: [\n\t\t{\n\t\t\tid: \"output_1\",\n\t\t\tbands: 1,\n\t\t\tsampleType: \"FLOAT32\",\n\t\t\tnodataValue: NaN,\n\t\t},\n\t\t{\n\t\t\tid: \"dataMask\", \n\t\t\tbands: 1,\n\t\t}\n\t],\n     mosaicking: Mosaicking.ORBIT\n   }\n }\n\n\tfunction updateOutput(output, collection) {\n\t  output.output_1.bands = collection.scenes.length\n\t}\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\t//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 }"
}'

evalscript:

function setup() {
   return {
	 input: [{
	   bands: ["B04", "B08"],
	   units: "DN"
	 }],
	 output: [
		{
			id: "output_1",
			bands: 1,
			sampleType: "FLOAT32",
			nodataValue: NaN,
		},
		{
			id: "dataMask", 
			bands: 1,
		}
	],
	 mosaicking: Mosaicking.ORBIT
   }
 }

	function updateOutput(output, collection) {
	  output.output_1.bands = collection.scenes.length
	}

 function evaluatePixel(samples) {
	// Precompute an array to contain NDVI observations
   var n_observations = samples.length;
   let ndvi = new Array(n_observations).fill(0);
  
	//Fill the array with NDVI values
   samples.forEach((sample, index) => {
	 ndvi[index] = (sample.B08 - sample.B04) / (sample.B08 + sample.B04) ;
   });
					 
   return ndvi;
 }

Can you always please report any errors you get in the request? What does the request return that you do not expect?

sure, sorry for any inconvenience
for the latter json-request and evalscript, when they get executed in the request builder, i receive the error in the screen shot below, please have a look

imgae:

It seems like you are not using the JSON request body that you pasted into your post. Can you confirm that you are executing the request which you last posted?

it seems that i did not update the evalscript. however, now i am receiving the error posted in the screen-shot

screen-shot:

If you remove the datamask output in the setup function everything should work:

function setup() {
   return {
	 input: [{
	   bands: ["B04", "B08"],
	   units: "DN"
	 }],
	 output: [
		{
			id: "output_1",
			bands: 1,
			sampleType: "FLOAT32",
			nodataValue: NaN,
		}
	],
	 mosaicking: Mosaicking.ORBIT
   }
 }

	function updateOutput(output, collection) {
	  output.output_1.bands = collection.scenes.length
	}

 function evaluatePixel(samples) {
	// Precompute an array to contain NDVI observations
   var n_observations = samples.length;
   let ndvi = new Array(n_observations).fill(0);
  
	//Fill the array with NDVI values
   samples.forEach((sample, index) => {
	 ndvi[index] = (sample.B08 - sample.B04) / (sample.B08 + sample.B04) ;
   });
					 
   return ndvi;
 }

thank you. however, i have some questions:

1- would you please simply explain to me, how come despite it is specified in the evalscript output object that the number of bands is one, i wil still be able to receive array of ndvis?

2-can i replace let ndvi = new Array(n_observations).fill(0) with let ndvi = new Array(n_observations).fill(NaN) ?

  1. This is because of the updateOutput function, which updates the number of returned bands while the evalscript is running
  2. Yes, that should be possible.

so, now i will receive a tiff where each pixel of it assigned to the corresponding ndvi value ranges betweem -1,1, right?