0

I am very new to Google Earth Engine. I manipulated this code to my use from my class mini project. I am trying to export a date associated with the image along side the ET value after I performer a Reducer.mean() for a every feature. For now, I have accomplished this by adding a separate band for Year, Month and Day for each image. But I feel this is a crude way of performing this task. Ideally, I would like to export the Date as a string in a single column for each image. So I manipulated my code a little bit.

In order to accomplish this I added line 107 and 108 where I get the date of each image and then add that as a dictionary with name "date_as_string". Having done this on loop, I call this dictionary later while exporting (line 153). But this give me an Error (given below). I am not sure what I am doing wrong.

If my approach is wrong, is there a efficient way to export the date of each image as string in separate column?

Also, what is the best way to preview my analysis data I want to export before I export to CSV? Any suggestions regarding this? Following are the relevant information:

Asset: https://code.earthengine.google.com/?asset=users/memugal33/studyarea__pnw

Code link: https://code.earthengine.google.com/56e46e8769ab2e05183079e8ffa58df8

Error I get:

Error in map(ID=0): Image.date: Image '0' does not have a 'system:time_start' property.

Code:


var counties = ee.FeatureCollection("users/memugal33/studyarea__pnw"),
    mod_ET = ee.ImageCollection("MODIS/006/MOD16A2");
    
var cnties = ee.FeatureCollection(counties); 
//print(cnties)
var start_date = '2001-01-01';
var end_date = '2020-12-31';
////////////////////////////////////////////////
/// add Date to an image
function addDate_to_image(image){

var d = (image.date().getRelative('day','month'))
var d2 = ee.Image.constant(d).uint16().rename('day')

var m = (image.date().getRelative('month','year'))
var m2 = ee.Image.constant(m).uint16().rename('month')

var y = image.date().format('YYYY')
y = ee.Number.parse(y)
var y2 = ee.Image.constant(y).uint16().rename('year')

  return image.addBands([d2,m2, y2]); /// The day, month and year is added as new bands
}
////////////////////////
///
/// add Date to an imageCollection/Time Series by using map(.) function
/// to recursively call the function addDate_to_image(.) defined above
//
//
function addDate_to_collection(collec){
  var C = collec.map(addDate_to_image);
  return C;
}


  function extract_ET(a_feature){
    var geom = a_feature.geometry();
    var newDict = {'original_polygon_1': geom};
        var imageC = mod_ET.filterDate(start_date, end_date)
                .select('ET')
                .filterBounds(geom)
                // Clip(.) function  is clipping the boundary of the given field.
                .map(function(image){return image.clip(geom)})
                // .filter('CLOUDY_PIXEL_PERCENTAGE < 90')
                .sort('system:time_start', true);
    imageC = addDate_to_collection(imageC);
    imageC = imageC.map(function(im){return(im.set(newDict))});           
    imageC = imageC.set({ 'original_polygon': geom,
                          'cnty_feat':a_feature});
 return imageC;
}  

//
// The function below (mosaic_and_reduce_IC_mean(.)) stiches
// the tiles that cover a polygon to create a complete image of a field
// and then reduces (i.e. takes averages of all) ET pixels values into one value for
// the field.
//
function mosaic_and_reduce_IC_mean(an_IC){
  an_IC = ee.ImageCollection(an_IC);
  
  var reduction_geometry = ee.Feature(ee.Geometry(an_IC.get('original_polygon')));
  var WSDA = an_IC.get('cnty_feat');
  var start_date_DateType = ee.Date(start_date);
  var end_date_DateType = ee.Date(end_date);
  //######**************************************
  // Difference in days between start and end_date
  var diff = end_date_DateType.difference(start_date_DateType, 'day');
  // Make a list of all dates
  var range = ee.List.sequence(0, diff.subtract(1)).map(function(day){
                                    return start_date_DateType.advance(day,'day')});
  // Funtion for iteraton over the range of dates
  function day_mosaics(date, newlist) {
    // Cast
    date = ee.Date(date);
    newlist = ee.List(newlist);

    // Filter an_IC between date and the next day
    var filtered = an_IC.filterDate(date, date.advance(1, 'day'));

    // Make the mosaic
    var image = ee.Image(filtered.mosaic());

    // Add the mosaic to a list only if the an_IC has images
    return ee.List(ee.Algorithms.If(filtered.size(), newlist.add(image), newlist));
  }

  // Iterate over the range to make a new list, and then cast the list to an imagecollection
  var newcol = ee.ImageCollection(ee.List(range.iterate(day_mosaics, ee.List([]))));
  //print("newcol 1", newcol);
  //######**************************************

  var reduced = newcol.map(function(image){
    
    var means = image.reduceRegions({
                                                        collection:reduction_geometry,
                                                        reducer:ee.Reducer.mean(), 
                                                        scale: 10  //Does this scale make any difference???
                                                      });
                                                      
        //// This two lines is intended to add Date as string in the image property //////     
        
        ///The idea is to name the dictionary name "date_as_string" and select
        ///"date_as_string" in the selectors while exporting to CSV
        means = means.map(function(f){return f.set({date_as_string: image.date().format("yyyy/MM/DD")})})
        return means.copyProperties(image);
        ////////////////////////////////////////////
                        
                          //return means;
                                          }
                        ).flatten();
                          
  reduced = reduced.set({ 'original_polygon': reduction_geometry,
                        'cnties':WSDA
                      });
  WSDA = ee.Feature(WSDA);
  WSDA = WSDA.toDictionary();
  
  // var newDict = {'WSDA':WSDA};
  reduced = reduced.map(function(im){return(im.set(WSDA))}); 
  return(reduced);
}
var Et_img_coll = cnties.map(extract_ET);
//print(Et_img_coll)

var allcnties = Et_img_coll.map(mosaic_and_reduce_IC_mean);
///////Visualizing For Preview purpose/////////
var allcnt = allcnties.first()
print(allcnt)

// var ET_chart = ui.Chart.feature.byFeature(allcnt, "ET")
// .setOptions({title: "ET MEAN",
// pointSize: 3});
// print(ET_chart);
////////////////////////////////////


var yourFileName = "ET_Final";
var FolderName = "rem_sens";
print(yourFileName)
Export.table.toDrive({
  collection: allcnties.flatten(),
  description: yourFileName,
  folder: FolderName,
  fileNamePrefix: yourFileName,
  fileFormat: 'CSV',
  // Provide the name of variables of interst to export.
  // Some of these names come from shapefile that we have added to imagecollection
  //
  ///Date_as_string is also selected
  selectors:["JURISDIC_2","name","day","month","year", "ET", "date_as_string"] 
});

1 Answer 1

0

This was a quite convoluted solution. Maybe you can simplify it like the below instead? See inline comments for explanations.

https://code.earthengine.google.com/fa6d784540a6c2c311914ed9e77ebd01

var startDate = '2001-01-01' // Pick a shorter date range while developing, to speed things up
var endDate = '2021-01-01' // Exclusive endDate
var etCollection = ee.ImageCollection("MODIS/006/MOD16A2") // Global images, no need to filter by bounds
  .filterDate(startDate, endDate) // Only include images in date range
  .select('ET') // Only care about ET
  
var featureCollection = ee.FeatureCollection("users/memugal33/studyarea__pnw")
  // .limit(2) // Just use a few features when developing, to speed things up
  .map(calculateMeans) // Calculate mean ET for every image in etCollection, for each feature
  .flatten() // Flattens the resulting collection of collections into a collection of features

print(featureCollection) // Print the collection before exporting, to "preview" it

Export.table.toDrive({
  collection: featureCollection,
  description: 'ET_Final',
  folder: 'rem_sens',
  fileNamePrefix: 'ET_Final',
  selectors: ['JURISDIC_2', 'et', 'date']
})


function calculateMeans(feature) {
  return etCollection
    .map(function (et) {
      return calculateMean(et, feature)
    })
    .filter(ee.Filter.notNull(['et'])) // Remove features without et
}

function calculateMean(et, feature) {
  var mean = et.reduceRegion({
    reducer: ee.Reducer.mean(), 
    geometry: feature.geometry(), 
    scale: 500, // Set the scale at same resolution as your images for maximum accuracy (smaller than that just makes it slower) 
    maxPixels: 1e13
  }).getNumber('ET')
  return feature.set({
    // Property name swill correspond to CSV column names
    // Tweak this for other date columns. 
    date: et.date().format('yyyy-MM-dd'), 
    et: mean
  })
}
1
  • Thank you very much for this code. Definitely much simpler than mine.
    – Samrat
    Mar 31, 2021 at 15:27

Your Answer

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

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