0

I have masked my landcover classes but I am unable to generate an ndvi time-series for these masked landcover classes. I am using the Copernicus 2019 land cover product and would like to start with one of the land cover masked say shrubs (LCclass20) and then chart the ndvi times series for this particular class in my study area. I am still new to GEE. I have also calculated the frequency and percentages of the landcover.

The link to my code is https://code.earthengine.google.com/?scriptPath=users%2Fwawerujohn%2FProject__Work%3ASamburu_Landcover_Editing

var globcover = ee.Image("COPERNICUS/Landcover/100m/Proba-V-C3/Global/2019")
.select('discrete_classification')

// Extract the landcover band
var landcover = globcover.select('discrete_classification');
    
// Clip the image to the polygon geometry
var landcover_roi = landcover.clip(geometry);
    
// Add a map layer of the landcover clipped to the polygon.
Map.addLayer(landcover_roi);
    
// Print out the frequency of landcover occurrence for the polygon.
var frequency = landcover.reduceRegion({
  reducer:ee.Reducer.frequencyHistogram(),
  geometry:geometry,
  scale:1000
});

// Select the classes you are interested in analyzing
//Shrub land cover
var LCclass20 = landcover_roi.eq(20); 

//Vegetation land cover
var LCclass30 = landcover_roi.eq(30); 

//Forest land cover
var LCclass126 = landcover_roi.eq(126)


print('Shrub', LCclass20);
print('Vegetation', LCclass30);
print('Forest', LCclass126);

Map.addLayer(LCclass20, {}, "Shrub");
Map.addLayer(LCclass30, {}, "Vegetation");
Map.addLayer(LCclass126, {}, "Forest");

// Function to mask cloud from built-in quality band
// information on cloud
//var maskcloud1 = function(image) {
//var QA60 = image.select(['QA60']);
//return image.updateMask(QA60.lt(1).divide(10000));
//};

// Filter collection to ROI and dates of interest
// Finally, apply the mask to every image in the collection using map
var S2 = ee.ImageCollection('COPERNICUS/S2')
.filterBounds(geometry)
.filterDate('2020-01-01','2020-01-31')
.map(function(image){
  return image.updateMask(LCclass20);
});

// Function to calculate and add an NDVI band
var addNDVI = function(image) {
return image.addBands(image.normalizedDifference(['B8', 'B4']));
};

// Add NDVI band to image collection
var S2 = S2.map(addNDVI);

// Extract NDVI band and create NDVI median composite image
var NDVI = S2.select(['nd']);
var NDVImed = NDVI.median(); 
print('S2',S2)

// Create palettes for display of NDVI
var visParams = {
  min: -0.1,
  max: 1.0,
  palette: [
    'FFBB22', 'FFFF4C', '648C00', 
    ],
};

var features =[
  ee.Feature(LCclass20),
  ee.Feature(LCclass30),
  ee.Feature(LCclass126),
];

// Create a time series chart.
//Map.centerObject(testPoint, 10)
var chart = ui.Chart.image.series({
    imageCollection: S2.select('S2'),
    region: LCclass20.geometry()
    }).setOptions({
      interpolateNulls: true,
      lineWidth: 1,
      pointSize: 3,
      title: 'NDVI over Time at a Single Location',
      vAxis: {title: 'NDVI'},
      hAxis: {title: 'Date', format: 'YYYY-MMM', gridlines: {count: 12}}
    })
print(chart)

//print(plotNDVI);


var dict = ee.Dictionary(frequency.get('discrete_classification'));
var sum = ee.Array(dict.values()).reduce(ee.Reducer.sum(),[0]).get([0]);
var new_dict = dict.map(function(k,v) {
  return ee.Number(v).divide(sum).multiply(100);
});
print('Land Cover (%)',new_dict);

print('landcover frequency', frequency.get('discrete_classification'));

Map.setCenter(37, 1, 8);

Map.addLayer(globcover, {}, "Land Cover");

    Export.image.toDrive({
      image: landcover_roi,
      description: 'Landcover',
      scale: 100,
      region: geometry,
      fileFormat: 'GeoTIFF',
      formatOptions: {
        cloudOptimized: true
      }
    });

1 Answer 1

2

The main problem is that you must use an ee.Feature object as the region argument for ui.Chart.image.series. The transformation of an ee.Image to an ee.Feature can be done using reduceToVectors(). Then you can unite all the polygons into a single feature using union() indicating the maxError argument allowed as a number. With this feature, then you can obtain the desired chart.

Another problem you might find is that the number of pixels included in the transformation from image to feature is very large; thus, the console will show an error in this respect. To avoid this error you can set one or several of the following options: 1) change the maxPixels argument to a higher value, 2) set the bestEffort argument to true, 3) set the tileScale argument to a higher value and 4) set the scale argument to a higher value. Here's the working code using the changing the scale and maxPixels option.

Finally, in the chart you'll see various observations for each date because there are several images for the same date, so each point corresponds to the polygon's NDVI median for each image.

var LCclass20 = landcover_roi.eq(20); 
// Update mask to landcover_roi to stay only with the LCclass20 pixels
// Then transform it to ee.Feature
var LCclass20Vec = landcover_roi.updateMask(LCclass20)
.reduceToVectors({
  scale: 1200,
  maxPixels: 1e11
});
// Make a union of all polygons into a single one
LCclass20Vec = LCclass20Vec.union(1000);

//... other part of the script

// Make chart selecting the 'nd' band, indicate the desired reducer to apply over the complete polygon and the desired scale 
var chart = ui.Chart.image.series({
    imageCollection: S2.select('nd'),
    region: LCclass20Vec,
    reducer: ee.Reducer.median(),
    scale: 120
    }).setOptions({
      interpolateNulls: true,
      lineWidth: 1,
      pointSize: 3,
      title: 'NDVI over Time at a Single Location',
      vAxis: {title: 'NDVI'},
      hAxis: {title: 'Date', format: 'YYYY-MMM', gridlines: {count: 12}}
    });
print(chart);
1
  • how could I go about removing or merging the multiple NDVI values for the same date in GEE. I have been trying some methods but it is not working. Might you have an idea of how to go about this. Kindly see the question elaborated on this link gis.stackexchange.com/q/402002/181433?sem=2
    – Shiraz
    Jun 22, 2021 at 19:58

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.