Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Double loop with map() function in Google Earth Engine

In Google Earth Engine Developer's Guide, there is a recommendation to avoid for() loops. They recommend to use map() function as this example:

// to avoid
var clientList = [];
for(var i = 0; i < 8; i++) {
  clientList.push(i + 1);
}
print(clientList);

// to use
var serverList = ee.List.sequence(0, 7);
serverList = serverList.map(function(n) {
  return ee.Number(n).add(1);
});
print(serverList);

I'm trying to select MODIS scenes from each month/year prior to compute VCI. So, the approach I'd take is with a double loop:

modis = ee.ImageCollection("MODIS/MYD13A1");

var modis_list = [];
for(var i = 1; i <13; i++) {
  for(var j = 2000; j <2018; j++){
    modis_list.push(modis.filter(ee.Filter.calendarRange(i, i, 'month'))
                          .filter(ee.Filter.calendarRange(j, j, 'year')));
  }
}
print(modis_list);

Is there a way to replicate a double loop like this with map() function to reach a server-side approach?

like image 779
aldo_tapia Avatar asked Dec 07 '25 06:12

aldo_tapia


2 Answers

The easy way to do this is with a single map over the "months" you care about.

// Collect images for each month, starting from 2000-01-01.
var months = ee.List.sequence(0, 18*12).map(function(n) {
  var start = ee.Date('2000-01-01').advance(n, 'month')
  var end = start.advance(1, 'month')
  return ee.ImageCollection("MODIS/MYD13A1").filterDate(start, end)
})
print(months.get(95))

This will return a list of ImageCollections. Most months will have only 1 image, since MYD13A1 contains 16-day images, but some will have two. Month 95 is Jan of 2008 and has two.

Alternatively, you could join the collection with a collection of dates, but this is simpler.

And you should prefer filterDate over calendarRange when possible, as it's optimized.

like image 151
Noel Gorelick Avatar answered Dec 09 '25 20:12

Noel Gorelick


Assuming that you are just trying to understand GEE's map() function, and how would be the equivalent of a normal js for loop, the code would be:

var map_m = function(i) {
  i = ee.Number(i)
  var years = ee.List.sequence(2000, 2017)
  var filtered_col = years.map(function(j) {
    var filtered = modis.filter(ee.Filter.calendarRange(i, i, 'month'))
                        .filter(ee.Filter.calendarRange(j, j, 'year'))
    return filtered
  })
  return filtered_col
}

var months = ee.List.sequence(1, 12)
var modis_list2 = months.map(map_m).flatten()

This code replicates a normal for loop. First, it goes item by item of the years list, and then item by item of the months list, and then, once you have year and month, filter the collection and add it to a list (map does that automatically). As you use 2 map functions (one over years and the other over months), you get a list of lists, so to get a list of ImageCollection use the flatten() function. Somehow the printed objects are a bit different, but I am sure the result is the same.

like image 25
Rodrigo E. Principe Avatar answered Dec 09 '25 19:12

Rodrigo E. Principe



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!