3

Background

I would like to return percentile values for a multi-band image, using ee.Reducer.percentile().

For example, the image could look like this:

var image = ee.ImageCollection('LANDSAT/LT05/C01/T1')
  .filterDate('2008-01-01', '2008-03-01')
  .filter(ee.Filter.eq('WRS_PATH', 44))
  .filter(ee.Filter.eq('WRS_ROW', 34))
  .select('B1', 'B2')
  .toBands();

print(image);

In my case I am stacking an imageCollection (every image is one year), resulting in 18 bands:

var year_stack = imageCollectionYears.toBands();

In the R environment, I would use quantile(values(image), p = seq(0, 1, by = 0.2), na.rm = TRUE), which would return 6 quantile values, taken from all cell values in the raster image, regardless of layering.

Tried so far

I have applied the reducer to the image, but this returns percentile values for every band separately, rather than for all values in the image:

var percentiles = image.reduceRegion({
                  reducer:ee.Reducer.percentile([0, 20, 40, 60, 80, 100]),
                  bestEffort:true
  });

print(percentiles);

In my case, each band is an individual year, and the code returns percentile values for each year.

I have also tried to apply the reducer to my imageCollection, which returns an image with 6 bands.

var test = imageCollectionYears.reduce({
                  reducer:ee.Reducer.percentile([0, 20, 40, 60, 80, 100])

  });

enter image description here

I am struggling to retrieve the numbers of the percentiles in the returned image test, so I don't know if this worked (e.g. print(test.get("b1_p20")) prints null):

Question

How do I apply the reducer to all values, regardless of what band they are in, and return 6 percentile values? My aim is to get overall percentile values over all years, which I would then use for further analysis.

3

Here's some of the most terrible code I've ever written in EE. It really isn't a good idea to do it like this, and you will run out of memory when doing this at any larger scale. Maybe there's a better way to do this, that doesn't require every single pixel value to be in memory at once, but I cannot come up with one.

If you don't need the percentiles, maybe you could create multiple histograms, combine them, and get statistics from that? That should allow you to get similar type of information, and work for larger areas/more data.

var percentiles = ee.List(ee.ImageCollection(ee.ImageCollection('LANDSAT/LT05/C01/T1')
  .filterDate('2008-01-01', '2008-03-01')
  .filter(ee.Filter.eq('WRS_PATH', 44))
  .filter(ee.Filter.eq('WRS_ROW', 34))
  .select('B1', 'B2')
  .map(function (image) {
    var bands = image.bandNames().map(function (bandName) {
      return image.select(ee.String(bandName)).rename('band')
    })
    return ee.ImageCollection(bands)
  })
  .flatten())
  .iterate(function (image, acc) {
    var pixels = image.reduceRegion({
      reducer: ee.Reducer.toList(), 
      bestEffort: true
    }).get('band')
    return ee.List(acc).cat(pixels)
  }, ee.List([])))
  .reduce(ee.Reducer.percentile([0, 20, 40, 60, 80, 100]))

https://code.earthengine.google.com/10718c9b3187bd65925ab9eae16f1f06

1
  • Does exactly what I wanted, and no memory problems with my imageCollection! – Joris May 6 '20 at 9:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.