1

I have a set of points from around the world and I want to extract the pixel values from a set of images, giving information about the local environment, for each point. Then export the set of values as a .csv table.

My approach was to merge the images into a single multi-band image, then use SampleRegions to extract the values.

The problem is that if one of the images has a mask at the point location, the point is not included in the final results. So only points with no masked pixels are included in the output. I would like to include all the points, even if some of the bands have masked pixels.

//1. Set points: 
var fc_points = ee.FeatureCollection([
  ee.Feature(ee.Geometry.Point([-17.5558, 65.8674]),    {ID: '1'}),
  ee.Feature(ee.Geometry.Point(-7.85187, 54.15745),     {ID: '2'}),   
  ee.Feature(ee.Geometry.Point(177.469394, -38.968075), {ID: '3'}),
  ee.Feature(ee.Geometry.Point(-78.93655, -2.2895),     {ID: '4'}),     
  ee.Feature(ee.Geometry.Point(6.11699, 61.51734),      {ID: '5'}), 
          ]);

//2. Make multiband image 
var koppen = ee.Image("users/fsn1995/Global_19862010_KG_5m")
koppen = koppen.updateMask(koppen.lte(30)); // Koppen-Geiger climate class
var mean_precipitation = ee.Image("WORLDCLIM/V1/BIO").select('bio12') // World Climate: mean annual precipitation 
var Cop_dataset = ee.Image("COPERNICUS/Landcover/100m/Proba-V-C3/Global/2019").select('discrete_classification'); //Copernicus Land cover 
var landCover = ee.Image('COPERNICUS/CORINE/V20/100m/2012').select('landcover'); //CORINE landcover

// rename bands
    var climate = koppen.rename('KG_climate').toFloat();
    var precipitation = mean_precipitation.rename('WC_mean_precipitation_mmyr');
    var landcover_Copernicus = Cop_dataset.rename('GLC_Copernicus').toFloat();
    var landcover_CORINE = landCover.rename('LC_CORINE').toFloat();

// combine into single image
var merged_image = climate
      .addBands(precipitation)
      .addBands(landcover_Copernicus)
      .addBands(landcover_CORINE)


// Sample pixel values for each point, using SampleRegions: (requires: Image, points)
var sampled = merged_image.sampleRegions({
  collection: fc_points, // is a feature collection
  properties: ['ID'], // List of column names of sample points inside feature collection   (not compulsory).
  scale:30  // spatial resolution of band or image
});

print(sampled,'Sample_Region');


Export.table.toDrive({
  collection: sampled,
  description: 'sample_example_pt',
  fileFormat: 'CSV'
});

I tried to convert masked values to -99 by adding .unmask(-99) to each of the original images. But that didn't help.

My next idea would be to sample each layer separately, then join the results based on the ID property.

Any suggestions?

2 Answers 2

2

I think that with 'sampleRegions' method is not possible to solve this issue. We need to use 'sample' method when mapping point feature collection as follows:

//1. Set points: 
var fc_points = ee.FeatureCollection([
  ee.Feature(ee.Geometry.Point([-17.5558, 65.8674]),    {ID: '1'}),
  ee.Feature(ee.Geometry.Point(-7.85187, 54.15745),     {ID: '2'}),   
  ee.Feature(ee.Geometry.Point(177.469394, -38.968075), {ID: '3'}),
  ee.Feature(ee.Geometry.Point(-78.93655, -2.2895),     {ID: '4'}),     
  ee.Feature(ee.Geometry.Point(6.11699, 61.51734),      {ID: '5'}), 
          ]);

//2. Make multiband image 
var koppen = ee.Image("users/fsn1995/Global_19862010_KG_5m")
koppen = koppen.updateMask(koppen.lte(30)); // Koppen-Geiger climate class
var mean_precipitation = ee.Image("WORLDCLIM/V1/BIO").select('bio12') // World Climate: mean annual precipitation 
var Cop_dataset = ee.Image("COPERNICUS/Landcover/100m/Proba-V-C3/Global/2019").select('discrete_classification'); //Copernicus Land cover 
var landCover = ee.Image('COPERNICUS/CORINE/V20/100m/2012').select('landcover'); //CORINE landcover

// rename bands
var climate = koppen.rename('KG_climate').toFloat();
var precipitation = mean_precipitation.rename('WC_mean_precipitation_mmyr');
var landcover_Copernicus = Cop_dataset.rename('GLC_Copernicus').toFloat();
var landcover_CORINE = landCover.rename('LC_CORINE').toFloat();

// combine into single image
var merged_image = climate
      .addBands(precipitation)
      .addBands(landcover_Copernicus)
      .addBands(landcover_CORINE)

// Sample pixel values for each point, using SampleRegions: (requires: Image, points)
var sampled = merged_image.sampleRegions({
  collection: fc_points, // is a feature collection
  properties: ['ID'], // List of column names of sample points inside feature collection   (not compulsory).
  scale:30  // spatial resolution of band or image
});

print("Sample_Region", sampled);

var sampled2 = fc_points.toList(fc_points.size()).map(function (feat) {
  
  return ee.Algorithms.If(ee.FeatureCollection(merged_image.sample(ee.Feature(feat).geometry(), 30)).first(),
                          ee.FeatureCollection(merged_image.sample(ee.Feature(feat).geometry(), 30)).first(), 
                          ee.Feature(feat).set({'GLC_Copernicus': 'null',
                                                'KG_climate': 'null',
                                                'LC_CORINE': 'null',
                                                'WC_mean_precipitation_mmyr': 'null'
                          }));
  
});

print("sampled2", sampled2);

Export.table.toDrive({
  collection: ee.FeatureCollection(sampled2),
  description: 'sample_example_pt',
  fileFormat: 'CSV'
});

After running above script in GEE code editor, the task produces a CSV file with these characteristics:

enter image description here

Masked pixels properties are printed as null but, you can use -99; as it was above proposed.

0
0

I managed to do it using a sample, with dropNulls: false, and geometries: true, but with a horribly inelegant solution for doing spatial joins.

//1. Set points: 
var fc_points = ee.FeatureCollection([
  ee.Feature(ee.Geometry.Point([-17.5558, 65.8674]),    {ID: '1'}),
  ee.Feature(ee.Geometry.Point(-7.85187, 54.15745),     {ID: '2'}),   
  ee.Feature(ee.Geometry.Point(177.469394, -38.968075), {ID: '3'}),
  ee.Feature(ee.Geometry.Point(-78.93655, -2.2895),     {ID: '4'}),     
  ee.Feature(ee.Geometry.Point(6.11699, 61.51734),      {ID: '5'}), 
          ]);
          
//function: create region
var bufferPoly = function(feature) {
  return feature.buffer(20).bounds();  
};

var polygons = fc_points.map(bufferPoly)
print(polygons)

//2. Prepare images to sample from 
var koppen = ee.Image("users/fsn1995/Global_19862010_KG_5m")
koppen = koppen.updateMask(koppen.lte(30)); // Koppen-Geiger climate class
var mean_precipitation = ee.Image("WORLDCLIM/V1/BIO").select('bio12') // World Climate: mean annual precipitation 
var Cop_dataset = ee.Image("COPERNICUS/Landcover/100m/Proba-V-C3/Global/2019").select('discrete_classification'); //Copernicus Land cover 
var landCover = ee.Image('COPERNICUS/CORINE/V20/100m/2012').select('landcover'); //CORINE landcover

// rename bands
var climate = koppen.rename('KG_climate').toFloat();
var precipitation = mean_precipitation.rename('WC_mean_precipitation_mmyr');
var landcover_Copernicus = Cop_dataset.rename('GLC_Copernicus').toFloat();
var landcover_CORINE = landCover.rename('LC_CORINE').toFloat();

// 3. Sample pixel values for each point for each image individually, using Sample

  var sampled_climate = climate.sample({region: fc_points.geometry(), scale: 10, dropNulls: false, geometries: true})  
  var sampled_precip = precipitation.sample({region: fc_points.geometry(), scale: 10, dropNulls: false, geometries: true}) 
  var sampled_CORINE_LC = landcover_CORINE.sample({region: fc_points.geometry(), scale: 10, dropNulls: false, geometries: true})
  var sampled_COP_LC = landcover_Copernicus.sample({region: fc_points.geometry(), scale: 10, dropNulls: false, geometries: true}) 

print("sampled_CORINE", sampled_CORINE_LC);

//4. Spatial joins
// Define a spatial filter as geometries that intersect.
var spatialFilter = ee.Filter.intersects({
  leftField: '.geo',
  rightField: '.geo',
  maxError: 10
})

var saveAllJoin = ee.Join.saveAll({
  matchesKey: 'points'
})

// Apply joins successively to join the sampled collections together 
var Joined = saveAllJoin
  .apply({
    primary: polygons, 
    secondary: sampled_climate, 
    condition: spatialFilter
  })
  .map(function(polygon) {
    var label = polygon.get('ID')
    var points = ee.FeatureCollection(ee.List(polygon.get('points')))
      .map(function (point) {
        return point.set('ID', label)
      })
    return points.map(bufferPoly)
  }).flatten()
  

var Joined2 = saveAllJoin
  .apply({
    primary: Joined, 
    secondary: sampled_precip, 
    condition: spatialFilter
  })
  .map(function(polygon) {
    var label = polygon.get('ID')
    var climate = polygon.get('KG_climate')
    var points = ee.FeatureCollection(ee.List(polygon.get('points')))
      .map(function (point) {
        return point.set({'ID': label, 'KG_climate': climate})
      })
    return points.map(bufferPoly)
  }).flatten()

  
var Joined3 = saveAllJoin
  .apply({
    primary: Joined2, 
    secondary: sampled_CORINE_LC, 
    condition: spatialFilter
  })
  .map(function(polygon) {
    var label = polygon.get('ID')
    var climate = polygon.get('KG_climate')
    var COP_LC = polygon.get('WC_mean_precipitation_mmyr')
    var points = ee.FeatureCollection(ee.List(polygon.get('points')))
      .map(function (point) {
        return point.set({'ID': label, 'KG_climate': climate, 'WC_mean_precipitation_mmyr': COP_LC})
      })
    return points.map(bufferPoly)
  }).flatten()

  
var Joined4 = saveAllJoin
  .apply({
    primary: Joined3, 
    secondary: sampled_COP_LC, 
    condition: spatialFilter
  })
  .map(function(polygon) {
    var label = polygon.get('ID')
    var climate = polygon.get('KG_climate')
    var COP_LC = polygon.get('WC_mean_precipitation_mmyr')
    var COR_LC = polygon.get('LC_CORINE')
    var points = ee.FeatureCollection(ee.List(polygon.get('points')))
      .map(function (point) {
        return point.set({'ID': label, 'KG_climate': climate, 'WC_mean_precipitation_mmyr': COP_LC, 'LC_CORINE': COR_LC})
      })
    return points.map(bufferPoly)
  }).flatten()
  print(Joined4, 'Joined4')


// 5. Export results

Export.table.toDrive({
  collection: Joined4,
  description: 'sample_example_Joined',
  folder: 'example',
  fileFormat: 'CSV'
});

This exports a final .csv table like this: results

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.