I'm trying to perform PCA analysis on an NDVI time series which requires me to perform a centeredCovariance reduction across all the images in an image collection.

In order to be able to use the PCA method described in the Earth Engine guides (see: https://developers.google.com/earth-engine/guides/arrays_eigen_analysis) I have added the NDVI values of each image in my collection as bands in a single image which I then try to perform PCA on.

However, when I run the code it returns Array: Parameter 'values' is required. The problem seems to arise when I try to perform a centeredCovariance reduction which returns null.

What am I doing wrong?

full code: https://code.earthengine.google.com/edf99997dff139db0af594dbb5881a66

    //Select aoi
var point = ee.Geometry.Point(-108.466, 25.6842);

// Function to remove cloud and snow pixels
function maskCloudAndShadows(image) {
  var cloudProb = image.select('MSK_CLDPRB');
  var snowProb = image.select('MSK_SNWPRB');
  var cloud = cloudProb.lt(5);
  var snow = snowProb.lt(5);
  var scl = image.select('SCL'); 
  var shadow = scl.eq(3); // 3 = cloud shadow
  var cirrus = scl.eq(10); // 10 = cirrus
  // Cloud probability less than 5% or cloud shadow classification
  var mask = (cloud.and(snow)).and(cirrus.neq(1)).and(shadow.neq(1));
  return image.updateMask(mask);
// Adding a NDVI band
function addNDVI(image) {
  var ndvi = image.normalizedDifference(['B8', 'B4']).rename('ndvi')
  return image.addBands([ndvi])
var startDate = '2019-01-01'
var endDate = '2019-12-31'
// Use Sentinel-2 L2A data - which has better cloud masking
var collection = ee.ImageCollection('COPERNICUS/S2_SR')
    .filterDate(startDate, endDate)
    .select('ndvi') // I am only interested in the NDVI band

var first = collection.first();
Map.addLayer(first); //for visualisation

// Display the input imagery and the region in which to do the PCA.
var region = first.geometry();
Map.addLayer(ee.Image().paint(region, 0, 2), {}, 'Region');

//the purpose of the next section of code is to add turn each
//image in the time series into bands of a single image 
var list = collection.toList(collection.size());


var image = ee.Image(list.get(0));

print('test', image)

for (var i = 1; i < 71; i++) {
  var current = ee.Image(list.get(i))
  var image = image.addBands(current);

print(image) //to check this has worked (seems to be working)

// Set some information about the input to be used later.
var scale = 30;
var bandNames = image.bandNames();

// Mean center the data to enable a faster covariance reducer
// and an SD stretch of the principal components.
var meanDict = image.reduceRegion({
    reducer: ee.Reducer.mean(),
    geometry: region,
    scale: scale,
    maxPixels: 1e9

var means = ee.Image.constant(meanDict.values(bandNames));
var centered = image.subtract(means);
print('centered', centered) //this seems to work up until this point

// Collapse the bands of the image into a 1D array per pixel.
var arrays = centered.toArray();
print('arrays', arrays) //appears to work fine

// Compute the covariance of the bands within the region.
var covar = arrays.reduceRegion({
  reducer: ee.Reducer.centeredCovariance(),
  geometry: region,
  scale: scale,
  maxPixels: 1e9
print('covar', covar)  //!!! this is where the programme stops working
//returns 'null'

1 Answer 1


Your primary problem is that toArray() removes any pixels that have masked values anywhere in the stack. From the docs:

toArray(axis) - Concatenates pixels from each band into a single array per pixel. The result will be masked if any input bands are masked.

You are masking clouds and shadows in each image. Over the course of an entire year, there are no pixels in your region that didn't have at least some cloud. So all pixels end up masked.

This is what one random point looks like:

enter image description here

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.