My competency in GEE is quite low. I have calculated 2 NDVI layers (pre and post-disturbance NDVI). I have separated these NDVI layers into 4 classes according to NDVI values. Now I need to calculate the amount of area from each classes that transitioned into other classes from pre-NDVI to post-ndvi. Now i have no clue on how to do this part. Can anyone please advise me on how to proceed from the part I have finished?

My Script can be found here (https://code.earthengine.google.co.in/?scriptPath=users%2Fmd007%2FLearning_for_article_publication%3AGIS).

My assest (https://code.earthengine.google.co.in/?asset=users/md007/Sundaban_shapefile).

//var roi =(https://code.earthengine.google.co.in/?asset=users/md007/Sundaban_shapefile)
Map.centerObject(roi ,9);

//Created a water mask to work with the vegetative parts only.
var hansenImage = ee.Image('UMD/hansen/global_forest_change_2015');

// Select the land/water mask.
var datamask = hansenImage.select('datamask');

// Create a binary mask.
var watermask = datamask.eq(1);

//Cloud Masking
function prepSrL8(image) {
    var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0);
  var saturationMask = image.select('QA_RADSAT').eq(0);
  // Apply the scaling factors to the appropriate bands.
  var getFactorImg = function(factorNames) {
    var factorList = image.toDictionary().select(factorNames).values();
    return ee.Image.constant(factorList);
  var scaleImg = getFactorImg([
  var offsetImg = getFactorImg([
  var scaled = image.select('SR_B.|ST_B10').multiply(scaleImg).add(offsetImg);
  // Replace original bands with scaled bands and apply masks.
  return image.addBands(scaled, null, true)
    // .updateMask(aeroMask);

//'Pre Disaster NDVI'
// Landsat 8 Collection 2 surface reflectance for 'Pre Disaster NDVI'
var col = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
  .filterDate('2017-01-01', '2017-04-30')
var col = col

// Display the cloud-free median composite.
var visParams = {
  bands: ['SR_B4_median', 'SR_B3_median', 'SR_B2_median'],
  min: 0,
  max: .1
Map.setCenter(89.409, 21.962, 8);
Map.addLayer(col.clip(roi), visParams, 'Cloud-free mosaic of Pre Disaster NDVI');

// Create some visualization parameters
var ndviParams = {min: -1, max: 1, palette: ['blue', 'white', 'green']};
var diffParams = {min: -2, max: 2, palette:['red','white','green']};

// Create an NDVI image using bands the NIR and red bands (5 and 4)
var Pre_NDVI = col.normalizedDifference(['SR_B5_median', 'SR_B4_median']);
Map.addLayer(Pre_NDVI, ndviParams, "Pre Disaster NDVI");

//Classify Pre disaster NDVI into 5 classes
var ndvi1 = ee.Image(1)
          .where(Pre_NDVI.gt(0.0).and(Pre_NDVI.lte(0.2)), 1)
          .where(Pre_NDVI.gt(0.2).and(Pre_NDVI.lte(0.4)), 2)
          .where(Pre_NDVI.gt(0.4).and(Pre_NDVI.lte(0.6)), 3)
          .where(Pre_NDVI.gt(0.6), 4)
var ndvi1 = ndvi1.clip(roi).updateMask(watermask);

// Add map layers
Map.addLayer(ndvi1, {min: 1, max: 4, palette: ['#FFA500','#FFFF00', '#00FF00', '#008000']}, 'Pre Classified NDVI',true);

//Area calcualtion of each NDVI classess 
var areaImage1 = ee.Image.pixelArea().divide(1e6).addBands(ndvi1).updateMask(watermask);

// Using a Grouped Reducer
var areas1 = areaImage1.reduceRegion({
      reducer: ee.Reducer.sum().group({
      groupField: 1,
      groupName: 'classification',
    geometry: roi,
    scale: 100,
    tileScale: 4,
    maxPixels: 1e10
var classAreas1 = ee.List(areas1.get('groups'))

// Post Disaster NDVI
// Landsat 8 Collection 2 surface reflectance for 'Post Disaster NDVI'
var col1 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
  .filterDate('2018-01-01', '2018-04-30')
var col1 = col1

// Display the cloud-free median composite.
Map.setCenter(89.409, 21.962, 8);
Map.addLayer(col1.clip(roi), visParams, 'Cloud-free mosaic of Post Disaster NDVI');

// Create an Post Disaster NDVI image using bands the NIR and red bands (5 and 4)
var Post_NDVI = col1.normalizedDifference(['SR_B5_median', 'SR_B4_median']);
Map.addLayer(Post_NDVI, ndviParams, "Post Disaster NDVI");

// Classify the Post Disaster NDVI into 5 classes
var ndvi2 = ee.Image(1)
          .where(Post_NDVI.gt(0.0).and(Post_NDVI.lte(0.2)), 1)
          .where(Post_NDVI.gt(0.2).and(Post_NDVI.lte(0.4)), 2)
          .where(Post_NDVI.gt(0.4).and(Post_NDVI.lte(0.6)), 3)
          .where(Post_NDVI.gt(0.6), 4)
var ndvi2 = ndvi2.clip(roi).updateMask(watermask);

// Add map layers
Map.addLayer(ndvi2, {min: 1, max: 4, palette: ['#FFA500','#FFFF00', '#00FF00', '#008000']}, 'Post Classified NDVI',true);

//Area calcualtion of each NDVI classess 
var areaImage2 = ee.Image.pixelArea().divide(1e6).addBands(ndvi2).updateMask(watermask);

// Using a Grouped Reducer
var areas2 = areaImage2.reduceRegion({
      reducer: ee.Reducer.sum().group({
      groupField: 1,
      groupName: 'classification',
    geometry: roi,
    scale: 100,
    tileScale: 4,
    maxPixels: 1e10

var classAreas2 = ee.List(areas2.get('groups'))

1 Answer 1


There are two steps embedded in your question. Step one is to identify all pixels of a given pre-event NDVI class that changed to a different NDVI class after the event. Step two is to calculate the total area of those pixels.

Step one: You can do this by starting with making a binary map of changed pixels (look for all pixels where you saw a change in NDVI), then looking for pixels that have a value of 1 and that also overlap with a given NDVI class.

var changes = ee.Image(0).where(ndvi1.eq(ndvi2).not(),1)
var just1 = ee.Image(0).where(ndvi1.eq(1).and(changes.eq(1)),1)
var just2 = ee.Image(0).where(ndvi1.eq(2).and(changes.eq(1)),1)
var just3 = ee.Image(0).where(ndvi1.eq(3).and(changes.eq(1)),1)
var just4 = ee.Image(0).where(ndvi1.eq(4).and(changes.eq(1)),1)

Step two: You can do this using ee.Image.pixelArea(), which returns pixel areas as an image object. Since the map of changed pixels is binary, you can multiply it by the pixelArea map to get areas of changed pixels, then use a sum Reducer to add up all that area within your ROI:

var areas1 = just1.multiply(ee.Image.pixelArea())
var areas2 = just2.multiply(ee.Image.pixelArea())
var areas3 = just3.multiply(ee.Image.pixelArea())
var areas4 = just4.multiply(ee.Image.pixelArea())

Map.addLayer(areas1, {}, 'areas1')
var changed1 = areas1.reduceRegion({
  reducer: ee.Reducer.sum(),
  geometry: roi.geometry(),
  scale: 5,
  maxPixels: 1e9

The output (changed1) will give you the total area (in square meters) of pixels that used to be class 1 NDVI, but are now not class 1 NDVI. You could do that for all your classes. (Or, if you want, you could use a grouped reducer. This link has some good info about doing that.)

(Also, I would not say that your GEE competency is low, for what it's worth. I would not say this is a beginner-level script, and if you wrote it, or even if someone else wrote it and you're able to manipulate it, that's a pretty high level of competency.)

  • thank you for your awesome answer. In our suggested code, you meant to write ndvi1 in place of ndvi2, ndvi3 and ndvi4 ( line 3, line 4 and line 5 ), right? Another quick question: Is there any to determine which other classes a particular class transitioned to? Thank you.
    – Mohammed7
    May 8, 2022 at 7:40
  • Oh, yes, I did! That was a mistake. I'll edit it now, thank you. And yes, if you wanted to focus on changes from class 1 to class 2, for example, you could change the criteria for the just_ images - right now, the criteria for just1 are that ndvi1 has a value of 1 and that that pixel is in the changes image. You could add a criterion to the end: .and(ndvi2.eq(2)) to also isolate pixels where ndvi2 has a value of 2. Since earth engine doesn't support loops, I can't think of a faster way to do it than laying out each case one by one.
    – JeanAllen
    May 10, 2022 at 18:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.