3

Trying to detrend MODIS MOD13Q1 NDVI time series using a tutorial from Ozzy Campos (@ghidora77). This tutorial was for Landsat NDVI LANDSAT/LC08/C02/T1_L2 but I am trying to modify it for MODIS.

Successfully imported the data, parse it for quality control, masked, scaled and plotted the initial time series with a trend line. See the code in help3. Link to the asset: Oban.

Independent ('constant', 't') and dependent variables ('NDVI') have also been set. However, when trying to detrend the time series, I get the error below (see attached image). Because detrending doesn't work properly, I don't trust the resultant harmonic model.

Error generating chart: Projection error: Unable to compute intersection of geometries in projections and .

// List of the independent variable names.
var independents = ee.List(['constant', 't']);
// Name of the dependent variable.
var dependent = ee.String('NDVI');
// Compute a linear trend. This will have two bands: 'residuals' and
// a 2x1 band called 'coefficients' (columns are for dependent variables).
var trend = newndvi.select(independents.add(dependent))
  .reduce(ee.Reducer.linearRegression(independents.length(), 1));
Map.addLayer(trend, {}, 'Trend Array Image');

/////////////////////////////////////////////////
// **************** HELP!!!!!!! ***************

// Flatten the coefficients into a 2-band image.
var coefficients = trend.select('coefficients')
  .arrayProject([0])
  .arrayFlatten([independents]);

Compute a detrended series.

var detrended = newndvi.map(function(image) {
  return image.select(dependent).subtract(
    image.select(independents).multiply(coefficients).reduce('sum'))
    .rename(dependent)
    .copyProperties(image, ['system:time_start']);
});

var detrendedChart = ui.Chart.image.series(detrended, Oban, null, 250)
  .setOptions({
    title: 'Detrended MODIS Time Series at Oban',
    lineWidth: 1,
    pointSize: 3,
  });
print(detrendedChart);

Use these independent variables in the harmonic regression.

var harmonicIndependents = ee.List(['constant', 't', 'cos', 'sin']);
// Add harmonic terms as new image bands.
var harmonicLandsat = newndvi.map(function(image) {
  var timeRadians = image.select('t').multiply(2 * Math.PI);
    return image
      .addBands(timeRadians.cos().rename('cos'))
      .addBands(timeRadians.sin().rename('sin'));
  });
  

var harmonicTrend = harmonicLandsat
  .select(harmonicIndependents.add(dependent))
  // The output of this reducer is a 4x1 array image.
  .reduce(ee.Reducer.linearRegression({
   numX: harmonicIndependents.length(),
   numY: 1
  }));
  

Turn the array image into a multi-band image of coefficients.

var harmonicTrendCoefficients = harmonicTrend.select('coefficients')
  .arrayProject([0])
  .arrayFlatten([harmonicIndependents]);
// Compute fitted values.
var fittedHarmonic = harmonicLandsat.map(function(image) {
  return image.addBands(
    image.select(harmonicIndependents)
      .multiply(harmonicTrendCoefficients)
      .reduce('sum')
      .rename('fitted'));
});
// Plot the fitted model and the original data at the Oban.
print(ui.Chart.image.series(fittedHarmonic.select(['fitted', 'NDVI']), Oban,
      ee.Reducer.mean(), 250)
  .setSeriesNames(['NDVI', 'fitted'])
  .setOptions({
    title: 'Harmonic Model: Original and Fitted Values',
    lineWidth: 1,
    pointSize: 3
  })
);

Compute phase and amplitude.

var phase = harmonicTrendCoefficients.select('sin')
  .atan2(harmonicTrendCoefficients.select('cos'))
  // Scale to [0, 1] from radians.
  .unitScale(-Math.PI, Math.PI);
var amplitude = harmonicTrendCoefficients.select('sin')
  .hypot(harmonicTrendCoefficients.select('cos'))
  // Add a scale factor for visualization.
  .multiply(5);
// Compute the mean NDVI.
var meanNdvi = newndvi.select('NDVI').mean();
// Use the HSV to RGB transformation to display phase and amplitude.
var rgb = ee.Image.cat([phase, amplitude, meanNdvi]).hsvToRgb();
Map.addLayer(rgb, {}, 'Phase (hue), Amplitude (sat), NDVI (val)');

Plots and errors

1 Answer 1

4

You're hitting a bug related to a recent change. To work around it until the bug is fixed, assign a default projection to your reduced composites (e.g.: line 111).

var detrended = newndvi.map(function(image) {
  return image.select(dependent).subtract(
    image.select(independents).multiply(coefficients).reduce('sum'))
    .setDefaultProjection("EPSG:4326")
    .rename(dependent)
    .copyProperties(image, ['system:time_start']);
});
1
  • Perfect! This has fixed the problem. Very much appreciated.
    – Geo_CJ
    Commented Jan 26, 2023 at 17:02

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.