TransWikia.com

How to find top 10 greatest values in a GEE image collection?

Geographic Information Systems Asked by confused_coder on February 19, 2021

I’m trying to categorize temperature extremes for a region. Using the Hycom GEE dataset, I know that using a Reducer I can find the maximum value for each pixel across the image collection (see code below). However, I’d like to find that top 10 or 15 temperatures across each pixel in the collection and average them together to characterize a swath of the hottest days that year. It doesn’t look like you can specify how many of the max values you want with ee.Reducer.max(). I’m really new to GEE coding so I’m stumped. How can I get the i number of maximum values?

var dataset = ee.ImageCollection('HYCOM/sea_temp_salinity')
                  .filter(ee.Filter.date('2019-01-01', '2019-12-30'))
                  .filter(ee.Filter.neq('system:index','2017022312'))
                  .filter(ee.Filter.neq('system:index','2019030509'))
var temp_0 = dataset.select('water_temp_0', 'salinity_0');
var max = temp_0.reduce(ee.Reducer.max())

One Answer

Earth Engine does not currently have a "N greatest/least values" reducer. Without that, our remaining option is to use sorting, which has the disadvantage of requiring the entire collection to be brought into memory.

To get it to succeed I reduced your date range to the first six months:

var dataset = ee.ImageCollection('HYCOM/sea_temp_salinity')
                  .filter(ee.Filter.date('2019-01-01', '2019-06-30'))
                  .filter(ee.Filter.neq('system:index','2017022312'))
                  .filter(ee.Filter.neq('system:index','2019030509'));

Then, in order to do per-pixel sorting, we need to convert the collection into an array image (one image, each pixel in each band being a time series):

var temp_0_array = dataset.select('water_temp_0', 'salinity_0').toArrayPerBand();

Now, if you want just the average of the highest temperatures, you can sort them and take the last 10:

var ten_hottest_values = temp_0_array
    .select('water_temp_0')
    .arraySort()
    .arraySlice({start: -10});
var average = ten_hottest_values.arrayReduce(ee.Reducer.mean(), [0]);
Map.addLayer(average);

However, I guess from your .select('water_temp_0', 'salinity_0') that you might want to work with the salinity values corresponding to those temperatures. If so, then you can sort all the array bands using the temperature as the sort ordering like so:

var ten_hottest_values = temp_0_array
    .arraySort(temp_0_array.select('water_temp_0'))
    .arraySlice({start: -10});

But that will be a more expensive computation, so don't do it unless you need it.

https://code.earthengine.google.com/92ba786a02ae0e6f0c058e8b5781ed88


You may also be interested in ee.Reducer.intervalMean(); it does not take the mean of exactly 10 or 15 values, but the mean of values falling in a percentile range, which you can (if you wish) adjust to get approximately 10 values knowing the size of the collection. It will be significantly more efficient than the sorting approach above, but cannot do the "sorting salinity by temperature" computation if you want that.

var temp_0 = dataset.select('water_temp_0', 'salinity_0');
Map.addLayer(temp_0.reduce(ee.Reducer.intervalMean(90, 100)));

Correct answer by Kevin Reid on February 19, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP