1

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"]
})

1 Answer 1

2

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.

// filter and reduce (returns featureCollection)
  var data = image.reduceRegions({
    reducer: ee.Reducer.mean(),
    collection: swaner_sites,
    scale: 10 // Sentinel has NDVI pixel rez of 10 meters -> scale = 10
  })

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

1
  • You can accept your answer by clicking the grey tick icon. This shows others that the question is solved and will remove it from the list of unanswered questions. Apr 6, 2023 at 7:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.