[GIS] Google Earth Engine: ImageCollection (Error) Parameter ‘start’ is required

google-earth-engine

I try to calculate the monthly mean of the Soil Moisture of a point from year 2016 to 2017 from Google Earth. I use a function to calculate the mean by iterating the months since 2016, which is from 1 to 24, but Google earth engine indicates the error:

ImageCollection (Error) Parameter 'start' is required.

var point = ee.Geometry.Point([30.50,30.56]);

// Create a chart for SoilMoi100_200cm_inst trend in point 1.
var dataset = ee.ImageCollection('NASA/GLDAS/V021/NOAH/G025/T3H')
          .filterBounds(point)
          .filterDate('2016-01-01', '2017-12-01')
          .select('SoilMoi100_200cm_inst');

var months = ee.List.sequence(1, 24);
var start_year = 2016;
var start_date = '2016-01-01';

var byMonthYear = ee.ImageCollection.fromImages(
     months.map(function (m) {
     var start = ee.Date(start_date).advance(m, 'month'); // Starting date


      var y = start_year + Math.floor(m/13);


      var cal_m = (m % 12);
      if (cal_m === 0){
          cal_m=12;
      }
      var d = dataset
        .filter(ee.Filter.calendarRange(y, y, 'year'))
        .filter(ee.Filter.calendarRange(cal_m,cal_m, 'month'))
        .mean()
        .set('month', cal_m).set('year', y)
        .set('system:time_start', start.millis())

      return d;
}).flatten());

print(byMonthYear);

Best Answer

There are two main things to improve: 1) do not use client-side function such as if ... === ... in mapped (server-side) functions and on server side objects (m in this case). 2) you can get point (pixel) information using reduceRegion() on an image. As a last note, the end date is exclusive, so you will need to set the end date at 2018-01-01 to include the month of december 2017 completely.

You can correctly map over the image collection as follows:

// map over the months
var byMonthYear = ee.ImageCollection.fromImages(
     months.map(function (m) {
       // cast to an ee.Number()
      m = ee.Number(m);
      // get the start and end date by adding the amount of months to the start_date
      var start = ee.Date(start_date).advance(m.subtract(1), 'month'); // Starting date
      var end = ee.Date(start_date).advance(m, 'month'); // Ending date
      
      // make a mean composite per month
      var d = dataset.filterDate(start, end).mean()
        .set('month', start.format('MM')).set('year', start.format('YYYY'))
        .set('system:time_start', start.millis()).set('system:time_end', end.millis());
      // get the point information (reducer.first is sufficient, as you already made a mean composite per month)
      var pointMean = d.reduceRegion(ee.Reducer.first(), point, dataset.first().projection().nominalScale());  
      // set the dictionary as property and cast to an ee.Image, as setMulti returns an ee.Element.
      return ee.Image(d.setMulti(pointMean));
}));

Then print some information to the console:

// print the collection, point information and a graph over time
print('ImageCollection mean composites',byMonthYear);
print('mean point values', byMonthYear.aggregate_array('SoilMoi100_200cm_inst'));
print(ui.Chart.feature.byFeature(byMonthYear, 'system:time_start', 'SoilMoi100_200cm_inst'));

Link script