I am a Google Earth Engine beginning level user and I am attempting to build a plot showing median NDVI changes in Berlin over the research period (May 1st to September 30th for the years from 2017 to 2020). I have watched tutorials and read some other people´s codes as well as some questions users ask here and implemented this code. It seems to be working but I am struggling to understand a couple of things.

  1. NDVI is supposed to range between -1 and 1, however in the plot the values seem to be between 1.5 and 6 and it is not clear for me where these values are coming from and whether there is some mistake. Generally it looks correct as 2017 has higher NDVI values than 2018 for instance and the plot does represent that.
  2. The values on the horizontal axis have names 0_0 to 19_0 each value corresponding to the median NDVI value of an exact month, is there a simple way to rename them?

I have the geometry with 3038 vertices so I did not include it here. I do apologize if the questions are silly, the code is below:

var S2 = ee.ImageCollection('COPERNICUS/S2_HARMONIZED')

//apply the cloud mask
function maskS2(image) {
  var SCL = image.select('SCL');
  var mask = ee.Image(0).where(
      SCL.lt(8).and(SCL.gt(3)) ,1);
  return image.updateMask(mask);
var S2filtered= S2.map(maskS2);

//calculating NDVI
function addNDVI(image) {
  var ndvi = image.normalizedDifference(['B8','B4']);
  return image.addBands(ndvi.rename('ndvi'));
var S2filtered = S2filtered.map(addNDVI);
//selecting NDVI
var S2filtered = S2filtered.select('ndvi');
//clip to the geometry
var S2_clipped = S2filtered.map(function(img){ 
                    return img.clip(geometry)});

//Function to go through the months and calculate the median NDVI
var months = ee.List.sequence(5, 9);
var years = ee.List.sequence(2017, 2020);

// Map filtering and reducing across year-month combinations and convert to ImageCollection
var YearMonth = ee.ImageCollection.fromImages(
  years.map(function (y) {
        return months.map(function (m) {
            return S2
              .filter(ee.Filter.calendarRange(y, y, 'year'))
              .filter(ee.Filter.calendarRange(m, m, 'month'))

//Chart parameters
var chartparameters = {
 title: 'Monthly median NDVI',
  hAxis: {title: 'Month'},
  vAxis: {title: 'Median NDVI'},

//Plotting the chart
var chart = ui.Chart.image.seriesByRegion({
  imageCollection: YearMonth,
  regions: geometry,
  reducer: ee.Reducer.median(),
  scale: 50,
  xProperty: 'system:index',
  seriesProperty: 'PROJECT'

//Print chart to console

1 Answer 1


Two big errors:

You're using the wrong collection. There is no SCL band in the level 1 data, only in the level 2 data. (COPERNICUS/S2_SR_HARMONIZED)

Inside your mapped functions, you're using the original S2 collection, not the clipped, filtered, masked collection.

var YearMonth = ee.ImageCollection.fromImages(
    years.map(function (y) {
        return months.map(function (m) {
            return S2_clipped
              .filter(ee.Filter.calendarRange(y, y, 'year'))


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.