0

I am trying to create a timeseries chart in GEE and I keep having an error:

Error generating chart: Collection.map: A mapped algorithm must return a Feature or Image

What can be the reason for this error and how can I solve it ?

I am trying to create a kNDVI timeseries from each cluster on the site.

    var site = 
    /* color: #0b4a8b */
    /* displayProperties: [
      {
        "type": "rectangle"
      }
    ] */
    ee.Geometry.Polygon(
        [[[14.189235213951225, -18.464648340471996],
          [14.189235213951225, -19.8242220793087],
          [18.770534042076225, -19.8242220793087],
          [18.770534042076225, -18.464648340471996]]], null, false);

// 2. WorldCover and grassland mask
var worldcover = ee.Image('ESA/WorldCover/v200/2021');
var grassMask = worldcover.eq(30).clip(site);

// 3. Cloud/shadow mask function
function maskS2clouds(image) {
  var scl = image.select('SCL');
  var mask = scl.neq(3)  // 3 = cloud shadow
    .and(scl.neq(7))    // 7 = unclassified
    .and(scl.neq(8))    // 8 = cloud medium prob
    .and(scl.neq(9))    // 9 = cloud high prob
    .and(scl.neq(10))   // 10 = thin cirrus
    .and(scl.neq(11));  // 11 = snow
  return image.updateMask(mask);
}

// 4. Band scaling and kNDVI calculation
function addKNDVI(image) {
  // Scale bands
  var bands = ['B2','B3','B4','B5','B6','B7','B8','B8A','B11','B12'];
  var scaled = image.select(bands).divide(10000);
  image = image.addBands(scaled, null, true);
  
  // Calculate kNDVI
  var RED = image.select('B4');
  var NIR = image.select('B8');
  var sigma = 0.15;
  var kndvi = NIR.subtract(RED).pow(2)
    .divide(sigma * sigma * 4.0)
    .tanh()
    .rename('kndvi');
  return image.addBands(kndvi);
}

// 5. Sentinel-2 ImageCollection
var s2 = ee.ImageCollection('COPERNICUS/S2_SR_HARMONIZED')
  .filterBounds(site)
  .filterDate('2019-01-01', '2019-12-31')
  .map(maskS2clouds)
  .map(addKNDVI);

// 6. Create composite and mask to grassland
var composite = s2.select(['kndvi']).mean().clip(site);
var compositeGrass = composite.mask(grassMask);

// 7. Perform clustering
var training = compositeGrass.sample({
  region: site,
  scale: 10,
  numPixels: 1000,
  seed: 1
});

var clusterer = ee.Clusterer.wekaKMeans(15).train(training);
var clustered = compositeGrass.cluster(clusterer);

// 8. Time Series Analysis - NOW PROPERLY DEFINED
var timeSeriesData = s2.map(function(image) {
  // Add cluster band to each image
  var withCluster = image.select('kndvi').addBands(clustered.select('cluster'));
  
  // Calculate mean kNDVI per cluster
  var stats = withCluster.reduceRegion({
    reducer: ee.Reducer.mean().group({
      groupField: 1,
      groupName: 'cluster'
    }),
    geometry: site,
    scale: 10,
    maxPixels: 1e9
  });
  
  // Format results
  var date = ee.Date(image.get('system:time_start')).format('YYYY-MM-dd');
  var properties = {
    'date': date,
    'system:time_start': image.get('system:time_start')
  };
  
  // Add cluster means
  var groups = ee.List(stats.get('groups'));
  for (var i = 0; i < 15; i++) {
    var clusterData = ee.Dictionary(groups.get(i));
    var clusterNum = clusterData.get('cluster');
    var meanVal = clusterData.get('mean');
    properties['cluster_' + clusterNum] = meanVal;
  }
  
  return ee.Feature(null, properties);
});

// 9. Create and display chart
var chartData = timeSeriesData.map(function(feature) {
  var date = feature.get('date');
  var props = feature.toDictionary();
  
  return ee.List.sequence(1, 15).map(function(clusterNum) {
    return ee.Feature(null, {
      'date': date,
      'cluster': 'Cluster ' + clusterNum,
      'kndvi': props.get('cluster_' + clusterNum)
    });
  });
}).flatten();

var chart = ui.Chart.feature.groups({
  features: ee.FeatureCollection(chartData),
  xProperty: 'date',
  yProperty: 'kndvi',
  seriesProperty: 'cluster'
}).setOptions({
  title: 'kNDVI Time Series by Cluster',
  hAxis: {title: 'Date'},
  vAxis: {title: 'kNDVI'},
  lineWidth: 1,
  pointSize: 3
});

print(chart);

// 10. Export data
Export.table.toDrive({
  collection: timeSeriesData,
  description: 'Cluster_kNDVI_TimeSeries',
  fileFormat: 'CSV',
  selectors: ['date', 'system:time_start'].concat(
    ee.List.sequence(1, 15).map(function(i) {return 'cluster_' + i;})
  )
});

// 11. Display layers
Map.centerObject(site, 8);
Map.addLayer(clustered.randomVisualizer(), {}, 'Clusters');
Map.addLayer(site, {color: 'black'}, 'Study Area');
Map.addLayer(grassMask.updateMask(grassMask), {palette: ['green']}, 'Grassland Mask');

0

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.