1

Good Day

I am trying to generate an Enhanced Vegetation Index (EVI) in Google Earth Engine using Landsat 7 and 8 data. I have compiled the code below to filter the image collections, for a specific time period and region of interest, as well as to mask out a majority of the cloud cover in the images. I have then proceeded to calculate the EVI and add these values to the image collections as an attribute that I can select for further processing. I have undertaken this process separately for Landsat 7 and Landsat 8. However, since I am interested in the EVI that is generated from both these data sets I have merged these into one image collection.

Using this image collection, I would like to calculate the mean EVI value for a particular region of interest and then export these values along with the associated date (in the format dd-mm-yyyy) as a ".csv" file. I am aware that this is possible by clicking on the chart that is generated and downloading the associated ".csv" file or by exporting the data using the "Export.table.toDrive" function. However, none of these options provide the output in the structure as shown in the table below.

enter image description here

A sample of the code is provided here. Any assistance with this will be greatly appreciated. Kind Regards.

/// Add region of interest
var ROI = ee.FeatureCollection("users/shaedengokool/Eben_Sluis_15YO")
Map.addLayer(ROI, {}, 'ROI')
Map.centerObject(ROI, 10)

//1. Import the Landsat 8 TOA image collection.
var l8 = ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA')
              .filterDate('2002-01-01','2020-01-01')
              .filterBounds(ROI)
              .map(function(image){return image.clip(ROI)})
              
var L8cloudlessEVI = l8.map(function(image) {
  // Get a cloud score in [0, 100].
  var cloud = ee.Algorithms.Landsat.simpleCloudScore(image).select('cloud');

  // Create a mask of cloudy pixels from an arbitrary threshold.
  var mask = cloud.lte(10);

  // Compute EVI.
  var evi = image.expression(
    '2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', {
      'NIR': image.select('B5'),
      'RED': image.select('B4'),
      'BLUE': image.select('B2')
}).rename('EVI');

  // Return the masked image with an EVI band.
  return image.addBands(evi).updateMask(mask);
});

var L8EVI_collection = L8cloudlessEVI

//2. Import the Landsat 7 TOA image collection.
var l7 = ee.ImageCollection('LANDSAT/LE07/C01/T1_TOA')
              .filterDate('2002-01-01','2020-01-01')
              .filterBounds(ROI)
              .map(function(image){return image.clip(ROI)})

var L7cloudlessEVI = l7.map(function(image) {
  // Get a cloud score in [0, 100].
  var cloud = ee.Algorithms.Landsat.simpleCloudScore(image).select('cloud');

  // Create a mask of cloudy pixels from an arbitrary threshold.
  var mask = cloud.lte(10);

  // Compute EVI.
  var evi = image.expression(
    '2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', {
      'NIR': image.select('B4'),
      'RED': image.select('B3'),
      'BLUE': image.select('B1')
}).rename('EVI');

  // Return the masked image with an EVI band.
  return image.addBands(evi).updateMask(mask);
});

var L7EVI_collection = L7cloudlessEVI

var merged = ee.ImageCollection(L7EVI_collection.merge(L8EVI_collection));
print(merged, 'Merged')

var chart = ui.Chart.image.series({
    imageCollection: merged.select('EVI'),
    region: ROI,
    reducer: ee.Reducer.mean(),
    scale: 30,
})

print(chart, "EVI")

// get the mean value for the region from each image
var meanEVI = merged.map(function(image){
  var date = image.get('system:time_start');
  var mean = image.reduceRegion({
    reducer: ee.Reducer.mean(),
    geometry: ROI,
    scale: 30
  });
  // and return a feature with 'null' geometry with properties (dictionary)  
  return ee.Feature(null, {'mean': mean.get('EVI'),
                            'date': date})
});

// Export a .csv table of date, mean NDVI for watershed
Export.table.toDrive({
  collection: meanEVI,
  description: 'EVI_Timeseries',
  folder: 'Genus_Exchange_GEE_Data',
  fileFormat: 'CSV',
})

;

1 Answers1

3

In the code below I've added a date as an image property and exported it to a CSV. I also rearranged some of the code to decrease the computational time.

Here is the code:

var roi = ee.FeatureCollection("users/shaedengokool/Eben_Sluis_15YO")

// Define time of interest
var startdate = '2019-06-01' // insert
var enddate = '2020-06-01' // insert

var years = ee.List.sequence(ee.Date(startdate).get('year'), ee.Date(enddate).get('year'));

/// EVI calculations from Landsat

// This function masks clouds in Landsat 8 imagery.
function maskL8(im) {
  var qa = im.select('BQA');
  var mask = qa.eq(2720);
  return im.updateMask(mask).copyProperties(im);
}
// This function masks clouds in Landsat 7 imagery.
function maskL7(im) {
  var qa = im.select('BQA');
  var mask = qa.eq(672);
  return im.updateMask(mask).copyProperties(im);
}
// see: https://landsat.usgs.gov/sites/default/files/documents/landsat_QA_tools_userguide.pdf

var ls8toa = ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA')
.filterBounds(roi)
  .filterDate(startdate, enddate)
    .map(function(im) {return maskL8(im)})

var ls7toa = ee.ImageCollection('LANDSAT/LE07/C01/T1_TOA').filterBounds(roi).filterDate(startdate, enddate)
.map(function(im) {return maskL7(im)})
    
var ls7_evi = ls7toa.map(function(image) {
  var evi = image.expression(
    '2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', {
      'NIR': image.select('B4'),
      'RED': image.select('B3'),
      'BLUE': image.select('B1')
}).rename('EVI')
return image.addBands(evi)
})

var ls8_evi = ls8toa.map(function(image) {
  var evi = image.expression(
    '2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', {
      'NIR': image.select('B5'),
      'RED': image.select('B4'),
      'BLUE': image.select('B2')
}).rename('EVI')
return image.addBands(evi)
})

var landsat = ee.ImageCollection(ls7_evi.merge(ls8_evi));
var EVI = landsat.select(['EVI'])
print(EVI, 'EVI')

//create function to calculate mean values for each polygon
var pointsmean = function(image) {
  var means = image.reduceRegions({
    collection: roi, // used to be roi.select(['Id'])
    reducer: ee.Reducer.mean(),
    scale: 30
  })
  
  // assign time for every feature
  means = means.map(function(f) { return f.set({date: image.date().format("YYYY-MM-dd")}) })
  
  return means.copyProperties(image)
};

var finalEVI = EVI.map(pointsmean).flatten()
.sort('date', false)
.select(['date', 'mean'])
print(finalEVI.limit(100), 'final EVI')

Export.table.toDrive({
collection: finalEVI,
  description: 'EVI_'+startdate+'TO'+enddate,
fileFormat: 'CSV'
});
CrossLord
  • 574
  • 4
  • 20
  • Thank you greatly for your assistance. The code does run a lot faster now, however the output does not contain the "mean EVI" value. The three variables that are output are the "system:index", "date" and ".geo" Any idea what could be the issue on my end? Upon inspection of the merged feature collection in the Google Earth Engine console there is a "date" and "mean" property associated with each image, however, the mean is not calculated for all images (not sure why, maybe cloud cover?). Also is it possible to remove the timestamp from the date that is exported in the .csv file. – Shaeden Gokool Feb 16 '21 at 08:04
  • I'll look into it. Can you in the meantime please share your asset "ee.FeatureCollection("users/shaedengokool/Eben_Sluis_15YO")" by checking the "Anyone can read" box? That way everyone can access it. – CrossLord Feb 16 '21 at 08:21
  • The first image of the image collection you are exporting to a CSV needs to have a mean EVI value for it to create a column in the CSV file. In other words, the first image must not be empty. This can be achieved by changing the starttime of the analysis (to a cloud-free month). Any empty images that remain in the collection will indeed be empty due to the clouds. – CrossLord Feb 16 '21 at 08:29
  • I've removed the timestamp by adding the ".format("YYYY-MM-dd")" line in the code (see code above). – CrossLord Feb 16 '21 at 08:37
  • Thanks for the assistance once again. I have shared the asset. Please let me know if you can now access it. Changing the start time of the analysis to ensure that the image is not empty worked and a column of mean EVI has now been created. Everything now appears to be working as it should. – Shaeden Gokool Feb 16 '21 at 08:55
  • Great! I can now indeed access it. I've changed the code (above) one final time, to also sort the EVI mean values based on the date property; everything seems to be running smoothly now. – CrossLord Feb 16 '21 at 09:08