3

I would like to generate a collection of the 3 least cloudy granules for each Sentinel-2 tile within the bounds of a particular shapefile. It seems that this will require a function that iterates on each tile separately rather just using .sort, "Cloudy_Pixel_Percentage", and .mosaic to create a single mosaic of the least cloudy granule for each tile. So, I have created a script that identifies the distinct tiles:

    // Load the ROI table
    var table = 
    ee.FeatureCollection("users/theronmb/TTCS_Area_Crop_for_Sentinel-2");

    // Find the MGRS_TILES that overlap with the ROI for the time period 
    // of interest
    var collection = ee.ImageCollection("COPERNICUS/S2")
      .filter(ee.Filter.calendarRange(3,6,'month'))
      .filter(ee.Filter.calendarRange(2017,2017,'year'))
      .filterBounds(table)
      .distinct('MGRS_TILE')
    ;

    print(collection);

    // Get a specific metadata property.
    var tiles = ee.List(collection.aggregate_array('MGRS_TILE'));

From there, I was thinking to use a for loop to create the collections I need, iterating on the list of distinct tiles. Unfortunately, this simple loop I am using for testing does not seem to do anything (or even generate an error). Where am I going wrong?

    print(tiles.get(0)); // This works
    print(tiles.size()); // This works

    // Test iterating on the specific metadata property (does not work)
    for (var i = 0; i < tiles.size(); i = i + 1) {
    print(tiles.get(i));
    }
2

2 Answers 2

2

So, yes, best to use map() instead of loops in Earth Engine. With that guidance, I was able to develop the following script to optionally create either the 1st, 2nd, or 3rd least cloudy image collection for a given set of Sentinel-2 tiles.

// Load the ROI table
var table = ee.FeatureCollection("users/theronmb/TTCS_Area_Crop_for_Sentinel-2");

// Find the MGRS_TILES that overlap with the ROI for the time period of interest
var collection = ee.ImageCollection("COPERNICUS/S2")
  .filter(ee.Filter.calendarRange(3,6,'month'))
  .filter(ee.Filter.calendarRange(2017,2017,'year'))
  .filterBounds(table)
  .distinct('MGRS_TILE')
;

// Get the unique MGRS tile list
var tiles = ee.List(collection.aggregate_array('MGRS_TILE'));

/* Function to iterate through the image collection to pull out the nth 
least cloudy granuales for each target tile.*/
var fun = function(tile) {
  var S2 = ee.ImageCollection("COPERNICUS/S2")
    .filter(ee.Filter.calendarRange(3,6,'month'))
    .filter(ee.Filter.calendarRange(2017,2017,'year'))
    .filterMetadata('MGRS_TILE', 'equals', tile)
    .limit(3, 'CLOUDY_PIXEL_PERCENTAGE', true);
  var mylist= S2.toList(3);
  var s2 = ee.Image(mylist.get(0)); //change to 1 or 2 for 2nd or 3rd least cloudy
  return s2;
};

// Apply function to tile list
var filtered = tiles.map(fun);

// Create image collection from image list
var filtered = ee.ImageCollection(filtered);

print(filtered)
1

Theron,

You will want to dive deeper into the GEE documentation using for loops in GEE is not advised. You will want to map across your collection.

Here is a link to the client vs. server side discussion. Scroll down about half way on the page to see the discussion of mapping vs. looping.

https://developers.google.com/earth-engine/client_server

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.