0

In Google Earth Engine, is it possible to extract the annual second largest and second smallest value and construct an imagecollection? Apparently, there is no build-in reducer for this purpose. Here is my code for getting the min, please guide me on how to get the second max and min. Thank you!

Here is the code:

var startDate = ee.Date('2001-01-01'); // set start time for analysis
var endDate = ee.Date('2021-12-31'); // set end time for analysis

// calculate the number of year to process
var nyears = ee.Number(endDate.difference(startDate,'year'));

//init a time band
var createTimeBand= function(image) {
  return image.addBands(image.metadata('system:time_start')
  .divide(1e18))
 // .divide(1000*60*60*24*365))
}


var sst = ee.ImageCollection('MODIS/006/MOD11A1').select('LST_Day_1km')
            .filterDate(startDate, endDate)
            .map(createTimeBand)

var byyearMin = ee.ImageCollection(
  // map over each month
  ee.List.sequence(0,nyears).map(function (n) {
    // calculate the offset from startDate
    var ini = startDate.advance(n,'year');
    // advance just one month
    var end = ini.advance(1,'year');
    // filter and reduce
    return sst.filterDate(ini,end)
                .select(0).min()
              //  .sort('LST_Day_1km').reverse().first()
                .multiply(0.02)
                .subtract(273.15)
                .set('system:time_start', ini.millis());//convert time to number
}));
Li_GIS
  • 5
  • 3

1 Answers1

0
var startDate = ee.Date('2001-01-01'); // set start time for analysis
var endDate = ee.Date('2021-12-31'); // set end time for analysis

// calculate the number of year to process
var nyears = ee.Number(endDate.difference(startDate,'year'));

//init a time band
var createTimeBand= function(image) {
  return image.addBands(image.metadata('system:time_start')
  .divide(1e18))
 // .divide(1000*60*60*24*365))
}


var sst = ee.ImageCollection('MODIS/006/MOD11A1').select('LST_Day_1km')
            .filterDate(startDate, endDate)
            //.map(createTimeBand)
            
var byyearMin = ee.ImageCollection(
  // map over each month
  ee.List.sequence(0,nyears).map(function (n) {
    // calculate the offset from startDate
    var ini = startDate.advance(n,'year');
    // advance just one month
    var end = ini.advance(1,'year');
    
    var sortedDays = sst.filterDate(ini,end)
    .sort('LST_Day_1km')
    .toList(sst.size())
      
    var secondLargest = ee.List(sortedDays.get(1))
    var secondSmallest = ee.List(sortedDays.get(-1))
    
    var collection = ee.Image(secondLargest)
    .addBands(secondSmallest).rename(['secondLargest', 'secondSmallest'])
    .multiply(0.02)
      .subtract(273.15)
      return collection
      .set('system:time_start', ini.millis()) //convert time to number
      .set('Date', ee.Date(ini))
}));

print(byyearMin)
CrossLord
  • 574
  • 4
  • 20
  • Thanks a lot!!! It seems the e.List(sortedDays.get(1)) will put all values (including null values) in a list. So the returned result will contain many masked values. Is there a way to get the second max (while excluding masked/null values)? – Li_GIS Jan 18 '22 at 20:56
  • I printed out a map and chart and both show many years yield with null value when extracting second largest value. `Map.addLayer(ee.Image(byyearMin.first()),{min: 20, max: 40, palette: ['blue', 'limegreen', 'yellow', 'darkorange', 'red']}, 'Min Land Surface Temperature'); print( ui.Chart.image.series({ imageCollection: byyearMin, region: geometry, reducer: ee.Reducer.mean(), scale: 1000 }).setOptions({title: 'LST Min over time'}) );` @CrossLord – Li_GIS Jan 18 '22 at 22:39
  • thank you very much for the help! – Li_GIS Jan 27 '22 at 16:14