I am trying to retrieve monthly Sentinel-2 band data using zonal statistics (mean) and point buffer for further analysis.

I have created monthly median composites from January to December of 2017 using the .map function. However, when I call the variable "S2A" (which has the monthly composites), I get an error which says that S2A is not defined. I tried printing the S2A variable, and I realise that it has 12 monthly images with no properties.

I want S2A as an image collection with properties like band names, band values and system time properties.

My code is below:

// Year
var year = 2017;

// List of months parameter
// Name is the name of the month
// End is the last day of the month
var months = [
  { name: 'January', end: 31 },
  { name: 'February', end: 28 },
  { name: 'March', end: 31 },
  { name: 'April', end: 30 },
  { name: 'May', end: 31 },
  { name: 'June', end: 30 },
  { name: 'July', end: 31 },
  { name: 'August', end: 31 },
  { name: 'September', end: 30 },
  { name: 'October', end: 31 },
  { name: 'November', end: 30 },
  { name: 'December', end: 31 }

// Composite and export per months
months.map(function(month, index){
  // Name of the image
  var name = year + '_' + month.name;
  // Create start and end date from the composite
  var start = ee.Date.fromYMD(year, index + 1, 1);
  var end = ee.Date.fromYMD(year, index + 1, month.end);

// https://geetools.readthedocs.io/en/latest/cloud_mask.html (Documentation)

// For Shumaila Mam

// SIAC atmospheric correction module
var siac = require('users/marcyinfeng/utils:SIAC');

// Hollstein cloud mask module
var cld = require('users/fitoprincipe/geetools:cloud_masks')

var S2A = ee.ImageCollection('COPERNICUS/S2_HARMONIZED')
                  .filterDate(start, end)
                  // Pre-filter to get less cloudy granules.
                  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))
                   // Apply cloud-masking to each image
                  .map(cld.hollstein_S2(['shadow','cloud', 'cirrus']))
                  // Apply SIAC to each image
                 // Combine all masked, corrected images with a median

Map.addLayer(S2A,{bands:"B4,B3,B2", min: 0.0, max: 0.3, gamma: 1.4},name, false)

Map.addLayer(Points, {}, 'Points', false)

function zonalStats(ic, fc, params) {
  // Initialize internal params dictionary.
  var _params = {
    reducer: ee.Reducer.mean(),
    scale: null,
    crs: null,
    bands: [null],
    imgProps: null,
    imgPropsRename: null,
    datetimeName: 'datetime',
    datetimeFormat: 'YYYY-MM-dd HH:mm:ss'

  // Replace initialized params with provided params.
  if (params) {
    for (var param in params) {
      _params[param] = params[param] || _params[param];

  // Set default parameters based on an image representative.
  var imgRep = ic.first();
  var nonSystemImgProps = ee.Feature(null)
  if (!_params.bands) _params.bands = imgRep.bandNames();
  if (!_params.bandsRename) _params.bandsRename = _params.bands;
  if (!_params.imgProps) _params.imgProps = nonSystemImgProps;
  if (!_params.imgPropsRename) _params.imgPropsRename = _params.imgProps;

  // Map the reduceRegions function over the image collection.
  var results = ic.map(function(img) {
    // Select bands (optionally rename), set a datetime & timestamp property.
    img = ee.Image(img.select(_params.bands, _params.bandsRename))
      .set(_params.datetimeName, img.date().format(_params.datetimeFormat))
      .set('timestamp', img.get('system:time_start'));

    // Define final image property dictionary to set in output features.
    var propsFrom = ee.List(_params.imgProps)
      .cat(ee.List([_params.datetimeName, 'timestamp']));
    var propsTo = ee.List(_params.imgPropsRename)
      .cat(ee.List([_params.datetimeName, 'timestamp']));
    var imgProps = img.toDictionary(propsFrom).rename(propsFrom, propsTo);

    // Subset points that intersect the given image.
    var fcSub = fc.filterBounds(img.geometry());

    // Reduce the image by regions.
    return img.reduceRegions({
      collection: fcSub,
      reducer: _params.reducer,
      scale: _params.scale,
      crs: _params.crs
    // Add metadata to each feature.
    .map(function(f) {
      return f.set(imgProps);
  return results;

//Define parameters for the zonalStats function.
var params = {
  reducer: ee.Reducer.mean(),
  scale: 60,
  //crs: 'EPSG:5070',
  bands: [0, 1,2,3,4,5,6,7,8,9,10,11,12,13],
  bandsRename:['B1','B2', 'B3','B4','B5','B6','B7','B8','B8A','B11','B12','aot','tcwv','tco3'],

// Extract zonal statistics per point per image.
var ptsTopoStats = zonalStats(S2A, points, params);


  collection: ptsTopoStats,
  folder: 'Etse_sent_1',
  description: 'S1_2018',
  fileFormat: 'CSV'

Here is the link to my code

  • 1
    Welcome to GIS SE. As a new user, please take the Tour, which emphasizes the importance of asking One question per Question. If you give a numbered list of tasks, you're going to collect close votes.
    – Vince
    Commented Feb 4 at 23:02

1 Answer 1


A few observations about your code:

  • When using map, assign the result to a variable.
  • Load the modules outside the map.
  • Don't mix client-side operations with server-side objects, such as using the + operator to concatenate strings.
  • Don't use client-side methods inside a map, such as Map.addLayer(). The Code Editor only didn't show an error message because the map wasn't even executed – since the result wasn't stored in any variable.

The code below shows a simple way of computing monthly median composites, naming, and adding properties to the images.

// Load the modules here.
var siac = require('users/marcyinfeng/utils:SIAC');
var cld = require('users/fitoprincipe/geetools:cloud_masks');

var year = 2017;
var ethiopia = ee.FeatureCollection('users/S2967456/Ethiopia');

// Loads the collection and filters the images geographically and temporally.
var s2 = ee.ImageCollection('COPERNICUS/S2_HARMONIZED')
  .filter(ee.Filter.calendarRange(year, year, 'year'));

var months = ee.List.sequence(1, 12, 1);

var imageList = months.map(function(month) {
  // Filter images from month "month".
  var images = s2
    .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))
    .filter(ee.Filter.calendarRange(month, month, 'month'))
    // Use the functions of the "siac" and "cld" modules here.
    // .map(cld.hollstein_S2(['shadow','cloud', 'cirrus']))
    // .map(siac.get_sur)
  // Creates a median composite.
  var median = images.median();
  // Creates the string that will be used as the image name (id).
  var _y = ee.Number(year).format('%d');
  var _m = ee.Number(month).format('%d');
  var id = _y.cat('_').cat(_m);
  // Adds the properties to the composite.
  median = median.set({
    'year': year, 
    'month': month, 
    'system:id': id,
    'system:time_start': ee.Date.fromYMD(year, month, 1).millis()
  return median;

// Builds a ImageCollection from the list of images.
var result = ee.ImageCollection.fromImages(imageList);
print('result', result);


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.