Google Earth Engine – Exporting a CSV File to Google Drive with a Column ID from a FeatureCollection in GEE

exportgoogle-drivegoogle-earth-enginegoogle-earth-engine-javascript-apitime series

I need help, please. I exported a CSV file with evi2 time series from Sentinel-2 for multiple points using GEE. Each point (n = 2421) has a sample ID. I defined the table with coordinates and its respective IDs (plot_id) as follow:

var table = ee.FeatureCollection([
ee.Feature(ee.Geometry.Point([-42.7267,-13.73]), {plot_id: 1}),
ee.Feature(ee.Geometry.Point([-56.6053,-25.7097]), {plot_id: 2421})
]);

However I am not able to add a column in the CSV file containing the plot_id of each sample point.

I tried var plot_id = table.get('plot_id'); inside the function to generate a time-series, but returned NULL in the output.

CSV file I got.

How can I assign the respective plot_id to each point?

My code is here:

// Vou calcular o evi2 para a minha região de interesse, que não
// é um ponto, mas vários pontos.
//var table = ee.FeatureCollection("users/marciobcure/pontos_dexter").limit(4);

var table = ee.FeatureCollection([
ee.Feature(ee.Geometry.Point([-42.7267,-13.73]), {plot_id: 1}),
ee.Feature(ee.Geometry.Point([-73.5064,-7.4547]), {plot_id: 2}),
ee.Feature(ee.Geometry.Point([-56.6053,-25.7097]), {plot_id: 2421})
]);

print(table);

//ee.FeatureCollection("projects/ee-marciobcure/assets/coord_dexter").limit(3);
var geometry = table
//  .limit(2)
  .geometry();
  
// Sentinel 2
var idCollection = 'COPERNICUS/S2_SR_HARMONIZED';

//Definição da ImageCollection e Filtros Geoespaciais

 var img = ee.ImageCollection(idCollection)
        .filterDate('2015-01-01', '2022-01-31')//filtro de intervalo de período
        .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))//filtro de nuvens
        .filter(ee.Filter.bounds(geometry))
        //.mosaic();//função redutora
        .select(['B11', 'B8', 'B4']);

var s2evi2 = img.map(function(img){
   var date = img.get('system:time_start');
   var evi2 = img.expression(
    '2.5*(NIR-RED)/(NIR+(2.4*RED)+1)', {
      'NIR': img.select('B8').divide(10000),
      'RED': img.select('B4').divide(10000)
}).set('system:time_start', date).rename('EVI2');
//  return   ;
  return img.addBands(evi2);
});

// Create a function that takes an image, calculates the mean over a
// geometry and returns the value and the corresponding date as a 
// feature.
var createTS = function(img){
  var date = img.get('system:time_start');
  var plot_id = table.get('plot_id');
  var value = img.reduceRegion(ee.Reducer.mean(), geometry).get('EVI2');
  var ft = ee.Feature(null, {'system:time_start': date, 
                            'date': ee.Date(date).format('Y-M-d'), 
                            'value': value,
                            'plot_id': plot_id
  });
  return ft;
};

// // Aplica a função para cada imagem.
var EVI2 = s2evi2.map(createTS);
print(EVI2);

// // Export the time-series as a csv.
Export.table.toDrive({
    collection: EVI2,
    selectors: 'date, value, plot_id',
    description: 's2_do_Dexter',
    folder: 'S2_dexter_csv'
});

Best Answer

You will never get 'plot_id' values because you are mapping the wrong collection. You have to map the Feature Collection named table because it contains the 'plot_id' values. However, it requires a more elaborated approach.

For avoiding redundant calculations, I'm going to use the first ten elements of your table geometry (complete series is very huge with its 2421 elements) in following code:

// Vou calcular o evi2 para a minha região de interesse, que não
// é um ponto, mas vários pontos.
//var table = ee.FeatureCollection("users/marciobcure/pontos_dexter").limit(4);
var table = ee.FeatureCollection([
  ee.Feature(ee.Geometry.Point([-42.7267,-13.73]), {plot_id: 1}),
  ee.Feature(ee.Geometry.Point([-73.5064,-7.4547]), {plot_id: 2}),
  ee.Feature(ee.Geometry.Point([-73.3769,-7.7592]), {plot_id: 3}),
  ee.Feature(ee.Geometry.Point([-72.4456,-7.9039]), {plot_id: 4}),
  ee.Feature(ee.Geometry.Point([-71.2461,-8.0508]), {plot_id: 5}),
  ee.Feature(ee.Geometry.Point([-69.9989,-8.5072]), {plot_id: 6}),
  ee.Feature(ee.Geometry.Point([-72.8831,-8.565]), {plot_id: 7}),
  ee.Feature(ee.Geometry.Point([-69.2594,-8.7492]), {plot_id: 8}),
  ee.Feature(ee.Geometry.Point([-72.2669,-9.0389]), {plot_id: 9}),
  ee.Feature(ee.Geometry.Point([-68.4986,-9.2108]), {plot_id: 10})
]);

print(table);

Map.addLayer(table);
Map.centerObject(table);

//ee.FeatureCollection("projects/ee-marciobcure/assets/coord_dexter").limit(3);
var geometry = table
//  .limit(2)
  .geometry();
  
// Sentinel 2
var idCollection = 'COPERNICUS/S2_SR_HARMONIZED';

//Definição da ImageCollection e Filtros Geoespaciais

var col = ee.ImageCollection(idCollection)
        .filterDate('2015-01-01', '2022-01-31')//filtro de intervalo de período
        .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))//filtro de nuvens
        .select(['B11', 'B8', 'B4']);

col = col.filter(ee.Filter.bounds(geometry));

Map.addLayer(col);
print("col", col);

var table_list = table.toList(table.size());

var sizeCol_plotId = table_list.map(function (ele) {
  
  return [col.filter(ee.Filter.bounds(ee.Feature(ele).geometry())).size(),
          ee.Feature(ele).get('plot_id')];
  
});

print(sizeCol_plotId);

Above code returns the size of each Image Collection that intersects each feature geometry. It also returns the 'plot_id' paired with these Image Collections. After running above code, I got following result:

enter image description here

What does this mean? Only for the first point (plot_id = 1), there are 137 images in its respective Image Collection, 67 images for the second point and so on. On the other hand, there are image areas with three, two or one points.

So, the complete code for exporting a CSV file to Drive with a column ID from a Feature Collection in GEE is as follows:

// Vou calcular o evi2 para a minha região de interesse, que não
// é um ponto, mas vários pontos.
//var table = ee.FeatureCollection("users/marciobcure/pontos_dexter").limit(4);
var table = ee.FeatureCollection([
  ee.Feature(ee.Geometry.Point([-42.7267,-13.73]), {plot_id: 1}),
  ee.Feature(ee.Geometry.Point([-73.5064,-7.4547]), {plot_id: 2}),
  ee.Feature(ee.Geometry.Point([-73.3769,-7.7592]), {plot_id: 3}),
  ee.Feature(ee.Geometry.Point([-72.4456,-7.9039]), {plot_id: 4}),
  ee.Feature(ee.Geometry.Point([-71.2461,-8.0508]), {plot_id: 5}),
  ee.Feature(ee.Geometry.Point([-69.9989,-8.5072]), {plot_id: 6}),
  ee.Feature(ee.Geometry.Point([-72.8831,-8.565]), {plot_id: 7}),
  ee.Feature(ee.Geometry.Point([-69.2594,-8.7492]), {plot_id: 8}),
  ee.Feature(ee.Geometry.Point([-72.2669,-9.0389]), {plot_id: 9}),
  ee.Feature(ee.Geometry.Point([-68.4986,-9.2108]), {plot_id: 10})
]);

print(table);

Map.addLayer(table);
Map.centerObject(table);

//ee.FeatureCollection("projects/ee-marciobcure/assets/coord_dexter").limit(3);
var geometry = table
//  .limit(2)
  .geometry();
  
// Sentinel 2
var idCollection = 'COPERNICUS/S2_SR_HARMONIZED';

//Definição da ImageCollection e Filtros Geoespaciais

var col = ee.ImageCollection(idCollection)
        .filterDate('2015-01-01', '2022-01-31')//filtro de intervalo de período
        .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))//filtro de nuvens
        .select(['B11', 'B8', 'B4']);

col = col.filter(ee.Filter.bounds(geometry));

Map.addLayer(col);
print("col", col);

var table_list = table.toList(table.size());

var newCol = table_list.map(function (ele) {
  
  var new_col = col.filter(ee.Filter.bounds(ee.Feature(ele).geometry()));
  
  var getData = new_col.toList(new_col.size()).map(function (e) {
    
    var date = ee.Date(ee.Image(e).get("system:time_start")).format().slice(0,10);
    
    var evi2 = ee.Image(e).expression(
    '2.5*(NIR-RED)/(NIR+(2.4*RED)+1)', {
      'NIR': ee.Image(e).select('B8').divide(10000),
      'RED': ee.Image(e).select('B4').divide(10000)
    }).rename('EVI2');
    
    var value = ee.Image(evi2).reduceRegion(ee.Reducer.mean(), ee.Feature(ele).geometry()).get('EVI2');
    
    var ft = ee.Feature(null, {'date': date, 
                               'value': value,
                               'plot_id': ee.Feature(ele).get('plot_id')
      
    });
    
    return ft;
    
  });
  
  return getData;
  
});

print(newCol);

// // Export the time-series as a csv.
Export.table.toDrive({
    collection: ee.FeatureCollection(newCol.flatten()),
    selectors: 'date, value, plot_id',
    description: 's2_do_Dexter',
    folder: 'S2_dexter_csv'
});

After running above code in GEE, I got following CSV file. It contains 995 records with corresponding date, EVI value and plot_id.

enter image description here