TransWikia.com

How to loop through each feature in a shapefile in Google Earth Engine?

Geographic Information Systems Asked on March 8, 2021

I have written a script which calculates the mean NDVI, NDWI, and NDDI (Normalized Difference Drought Index) values for a given county in a specified time period. These values are then outputted to a graph. So far I have been testing the script using a shapefile of just one county.

My problem is that I need the script to run over all 78 counties in the country (South Sudan). I have loaded the counties shapefile (all 78) as an asset named ‘aoi’ and created a list based on the county names:

var countyList = aoi.aggregate_array('admin2RefN')

I’m new to GEE and JavaScript and don’t know how to create a loop which goes through each county in the shapefile and outputs a separate graph for each county.

If someone could explain how this can be done it would be very helpful.

Here is my full code:

var countyList = aoi.aggregate_array('admin2RefN')

//------------------------------- SPECIFY DATE RANGE --------------------------//

// Specify the date range required
var startDate = ee.Date('2020-01-01');
var endDate = ee.Date('2021-01-01'); 
print('Observations begin on: ', startDate.format('YYYY-MM-dd'),
      'and end on: ', endDate.format('YYYY-MM-dd'));
      

// Calculate the number of months to process
var nMonths = ee.Number(endDate.difference(startDate,'month')).round();
print ('Number of months to process: ', nMonths)


//------------------------------- REQUIRED FUNCTIONS --------------------------//

// Function to create NDVI & NDWI bands
var addIndices = function(image) {
    var ndvi = image.normalizedDifference(['B2', 'B1']).rename('NDVI')
    var ndwi = image.normalizedDifference(['B2', 'B7']).rename('NDWI')
  return image.addBands([ndvi,ndwi]);
};

// Function to create NDDI band
var addNDDI = function(image) {
    var nddi = image.normalizedDifference(['NDVI', 'NDWI']).rename('NDDI')
  return image.addBands(nddi);
};

// Helper function to extract the QA bits
function getQABits(image, start, end, newName) {
 // Compute the bits we need to extract.
 var pattern = 0;
 for (var i = start; i <= end; i++) {
 pattern += Math.pow(2, i);
 }
 // Return a single band image of the extracted QA bits, giving the band
 // a new name.
 return image.select([0], [newName])
 .bitwiseAnd(pattern)
 .rightShift(start);
}
 
// Function to mask out cloudy pixels
function maskQuality(image) {
 // Select the QA band.
 var QA = image.select('StateQA');
 // Get the internal_cloud_algorithm_flag bit.
 var internalQuality = getQABits(QA,8, 13, 'internal_quality_flag');
 // Return an image masking out cloudy areas.
 return image.updateMask(internalQuality.eq(0));
}


//---------------------- LOAD MODIS IMAGE COLLECTION -------------------------//

var modis = ee.ImageCollection('MODIS/006/MOD09A1')
                  .filter(ee.Filter.date(startDate, endDate))
                  .select(['sur_refl_b01','sur_refl_b02','sur_refl_b03',
                           'sur_refl_b04','sur_refl_b05','sur_refl_b06',
                           'sur_refl_b07','StateQA'],
                          //rename band names
                          ['B1','B2','B3','B4','B5','B6','B7','StateQA'])
                  .map(maskQuality)
                  .map(addIndices)
                  .map(addNDDI)
                  .map(function(image) { return image.clip(aoi); });

// Create composite image from MODIS collection
var modisCom = modis.median();
print('Basic band info: ', modisCom);


//---------------------------------- GRAPHS ---------------------------------//

var byMonth = ee.ImageCollection(
  // map over each month
  ee.List.sequence(0,nMonths).map(function (n) {
    // calculate the offset from startDate
    var ini = startDate.advance(n,'month');
    // advance just one month
    var end = ini.advance(1,'month');
    // filter and reduce
    return modis.filterDate(ini,end)
                .select('NDDI','NDVI','NDWI').mean()
                .set('system:time_start', ini);
}));

// Plot full NDDI, NDVI, NDWI time series
print(
  ui.Chart.image.series({
    imageCollection: byMonth,
    region: aoi,
    reducer: ee.Reducer.mean(),
    scale: 500,
  })
  .setOptions({
      title: 'Average NDDI, NDVI, NDWI by month',
      hAxis: {title: 'Time Period'},
      vAxis: {title: 'Range'},
      pointSize: 0,
      lineSize: 3,
      colors: ['ee5859', '84bc7d', '5499c5'],
      curveType: 'function'
  }));

One Answer

You need client-side iteration to do this. Call aggregate_array() with a property that uniquely identify each element in your collection. Then evaluate() the result, to turn it into a client-side array. I normally use system:index, but here I used the name of the county, ADM2_NAME, to easily get the county name as a client-side string for use in the chart title. You can then iterate the client-side array, names, pick up each county from the collection based on name, and chart it. Wrap your charting code into a function that takes the county to chart as an argument.

https://code.earthengine.google.com/2053dfef17efa08df0f5594a36da496f

countyList.aggregate_array('ADM2_NAME').evaluate(function (names) {
  names.map(function (name) {
    var county = countyList
      .filter(ee.Filter.equals('ADM2_NAME', name))
      .first()
    chartAoi(county.geometry(), name)
  })
})  

function chartAoi(aoi, name) {
  // I pass the client-side `name` string, to use in the chart title

  // Your charting code goes here 
}

Answered by Daniel Wiell on March 8, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP