Google Earth Engine – ranking temperature anomalies

google-earth-engine

I am trying to rank the temperature anomalies in a time series. Basically, I would like to have a raster showing the position of year X (eg 2020) in a time series (eg first hottest (value=1), second hottest (value=2), 15th hottest,…). Let me try to explain better with an example. For a pixel I have the following anomalies for the last 5 years. Then the anomalies have been ranked (2019 is the hottest 'largest anomaly', 2020 is the second hottest,…)

enter image description here

I would like to produce a layer for the year 2020 where my pixel has the value 2 (rank) I have been able to produce a raster showing the hottest year in a TS but do not know how to produce the annual ranked value

This is how far I managed to get – it's just getting the year of the max anomaly:

var startYear = 1981
var endYear = 2020

// Dummy collection of anomalies to have shortest possible code to reproduce my question
var anom = ee.ImageCollection(
  ee.List.sequence(startYear, endYear)
    .map(function (year) {
      year = ee.Number(year)
      return ee.Image([
        ee.Image.random(year).multiply(10000).int16().rename('anom'),
        ee.Image(year).int16().rename('year')
      ]).set('year', year)
    })
)
print(anom, 'anomalies')

var ROI = Map.getBounds(true)
var YYmax = anom.qualityMosaic('anom')
print(YYmax, 'YYmax')
Map.addLayer(YYmax.clip(ROI), {
  bands: 'year',
  min: startYear,
  max: endYear,
  palette: ["LemonChiffon", "Gold", "Orange", "Red", "Maroon"]
}, 'YYmax')

https://code.earthengine.google.com/dd0447086b40fd85453c963b7ff9e50d

Here is my complete code https://code.earthengine.google.com/ea25c30f8724851e6ab0e946d8ed9e41

Can anybody help?

Best Answer

You can do this with some array image fiddling. That's always a bit tricky, and not very easy on the eyes. To understand the code in detail, I suggest that you add the intermediate array images to the map and inspect, to see what they contain.

var anomYearArray = anom
  .toArray() // Convert collection to 2D array image 
var anomArray = anomYearArray.arraySlice(1, 0, 1)
var anomYearSorted = anomYearArray
  .arraySort(anomArray) // Sort by anomaly
  
var rankArray = anomArray.not().not() // An array of 1
      .arrayAccum(0, ee.Reducer.sum()) // An array from 1 to number of anomalies
      .multiply(-1).add(anomArray.arrayLength(0)).add(1) // Reverse array
var anomYearRankArray = anomYearSorted.arrayCat(rankArray, 1)

var rankedAnom = ee.ImageCollection(
  ee.List.sequence(startYear, endYear)
    .map(function (year) {
      year = ee.Number(year)
      var yearMask = anomYearRankArray.arraySlice(1, 1, 2).eq(year)
      var yearImage = anomYearRankArray.arrayMask(yearMask)
        .arrayProject([1])
        .arrayFlatten([['anom', 'year', 'rank']])
        .set('year', year)
        .set('system:time_start', ee.Date.fromYMD(year, 1, 1))
      return yearImage
    })
)

var anom2020 = rankedAnom.filterMetadata('year', 'equals', 2020)
Map.addLayer(anom2020, {bands: 'rank', min: 1, max: endYear - startYear + 1}, 'rank 2020')

https://code.earthengine.google.com/6f3f70cec94d1541f4ef3cbb01327d79

Here it is plugged into your complete script: https://code.earthengine.google.com/6ca7568d2d1ceb0f90561af41aa7738a

Related Question