Getting some weird results for NDVI code that used to work on the EE. I'm trying to calculate mean NDVI values for a series a months within 6 polygons. When I run the code, I get the expected results, except that the first two polygons (in this case object ID 0 and 1) have the same exact means for every month… When I check other details of the output, such as the .geo field that specifies the objects geometry, they are different and as I would expect. But for some reason the NDVI calculation is always the same.
I'm not a great EE coder so I haven't been able to figure out why this would be happening with object ID 0 and 1 but not the rest of them. Anyone have any clues?
Reproduceable example —–
link to code: https://code.earthengine.google.com/a80276b72c8c9c23468840b514d36f5c
link to features: https://code.earthengine.google.com/?asset=users/marshallthewolf/efish_valleyBottoms
// Add NDVI band Function
var addNDVI = function(image) {
var ndvi = image.normalizedDifference(['B8', 'B4']).rename('NDVI');
return image.addBands(ndvi);
};
// ================================================
// Import Data and Calc NDVI Values
// ================================================
// Define boundary for Swaner Preserve
var swaner_sites = ee.FeatureCollection("users/marshallthewolf/efish_valleyBottoms");
Map.centerObject(swaner_sites);
// print(sites);
// Define Sentinel 2 collection
var sentinel2 = ee.ImageCollection('COPERNICUS/S2'); // "S2" contains the older data "S2_SR" does NOT!
// Add NDVI band to each image in the collection (with mapping)
//var sentinel2 = sentinel2.map(addNDVI).select('NDVI');
// Filter Sentinel collection for May-September for 2017-2022
var swaner_summer_ndvi = sentinel2
.filter(ee.Filter.calendarRange(2017, 2022, 'year'))
.filter(ee.Filter.calendarRange(5, 9, 'month'))
.filterMetadata('CLOUDY_PIXEL_PERCENTAGE',"less_than", 25)
.filterBounds(swaner_sites)
.sort('system:time_start', false)
// add NDVI and copy properties of the images
.map(function(image){
return image.normalizedDifference(['B8', 'B4']).rename("NDVI")
.set(image.toDictionary(image.propertyNames()));
});
print(swaner_summer_ndvi, 'NDVI');
// ================================================
// Build table of NDVI means and prepair to export
// ================================================
var startDate = ee.Date('2017-05-01'); // set analysis start time
var endDate = ee.Date('2022-10-01'); // set analysis end time
var bandName = 'NDVI';
// calculate the number of months to process
var nMonths = ee.Number(endDate.difference(startDate,'month')).round();
var timeSeries = ee.FeatureCollection(ee.List.sequence(0,nMonths).map(function (n){
// calculate the offset from startDate
var ini = startDate.advance(n,'month');
// advance just one month
var end = ini.advance(1,'month');
// check if there are images in time span
var image = ee.Image(ee.Algorithms.If({
condition: swaner_summer_ndvi.filterDate(ini,end).size().gte(1),
// the valid NDVI image
trueCase: swaner_summer_ndvi.filterDate(ini,end).mean(),
// make a constant non-valid NDVI value image
falseCase: ee.Image(-999).rename(bandName)
}));
// filter and reduce (returns featureCollection)
var data = image.reduceRegions({
reducer: ee.Reducer.mean(),
collection: swaner_sites,
scale: 1000
})
// add the date of the image to each feature
.map(function(feat){
return feat.set('system:time_start', ini.millis(),
'system:time_end', end.millis(),
'numbImages', swaner_summer_ndvi.filterDate(ini,end).size(),
'YYYMMdd', ini.format('YYYMMdd'),
"name", swaner_summer_ndvi.select("name"));
});
return data;
})).flatten();
// print to see if it is doing what we expect...
print(timeSeries.filter(ee.Filter.neq('mean',-999)))
// ================================================
// Export the table to the driver for further R coding
// ================================================
// Export the data to a table for further analysis
Export.table.toDrive({
collection:timeSeries,
description:"Swaner_NDVI_022823",
fileFormat:"CSV",
//selectors:["HRpcode","timeseries"]
})
Best Answer
Posting this for posterity and info for others.
In my reducer call I had the scale set way to high for some reason - possibly for faster computation I can't remember... My fix is below.
Once I changed the reducer scale from 1000, to 10 I started getting the answers I expected. So lesson learned, set you reducer scale = native pixel values of your imagery unless you are getting computational errors