Google Earth Engine – Create Histogram for S2 ImageCollection

google-earth-enginehistogramreducers

I'm trying to compute ONE histogram for an entire ImageCollection in Google Earth Engine (example code here: https://code.earthengine.google.com/b10f5136a79a6309e381ae11aa9b7431)
What I'm doing now to achieve the result I want, is to calculate the histograms for each individual image histogram1 and add them up – such as here in Python API:

for j in range(0,norm_size):
  print('Procressing Image #', j+1, ' out of ', norm_size)
  image = ee.Image(norm_list.get(j));
  histogram1 = image.reduceRegion(
      reducer = ee.Reducer.fixedHistogram(0,1,255),
      geometry = s2_norm.geometry(),
      maxPixels = 10e9
      ).get(band)
  try:
    dic = histogram1.getInfo()
    if j==0:
      for l in range(0,255):
        bins[0,l] = dic[l][0]
        counts[0,l] = dic[l][1] 
    else:
      for l in range(0,255):
        counts[0,l] = counts[0,l] + dic[l][1] 

  except (IndexError):
    print(j,'Empty')
    pass   

This works fine, but it takes AGES, because of the getInfo().

Is there a smart GEE way, to get one histogram for the entire Imagecollection, that is not an image but a simple list, such as in the example code?

Best Answer

A histogram is basically a list of paired values. So, you can map it with a function without a for/loop. Following code snippet has essential part of algorithm for producing histogram chart for the entire Imagecollection.

var s2_norm_lst = s2_norm.toList(s2_norm.size());

var allValues = s2_norm_lst.map(function (ele) {
  
  var histogram = ee.Image(ele).reduceRegion({
        reducer: ee.Reducer.fixedHistogram(0,1,255),
        geometry: s2_norm.geometry(),
        maxPixels: 10e9}
      ).get(band);
  
  return ee.List(ee.Array(histogram).toList());
  
});

allValues = ee.List(allValues).flatten();

var len = allValues.size();

var list = ee.List.sequence(0, len.subtract(1), 2);

var tot_list = list.map(function(ele){

  var start = ee.Number(ele).int(); 
  var end = ee.Number(ele).add(2).int(); 

  var new_list = ee.List([]);
  var element = ee.List(allValues.slice(start, end));

  new_list = new_list.add(element);

  return new_list.get(0);

});

//print(tot_list);

var allValues = tot_list.map(function (ele) {
  
  return ee.List(ele).get(0);
  
});

var allCounts = tot_list.map(function (ele) {
  
  return ee.List(ele).get(1);
  
});

var chart3 = ui.Chart.array.values({array: allCounts, axis: 0, xLabels: allValues})
                .setOptions({
                  title: 'Sentinel 2 normalized B2 band Histogram',
                  colors: ['blue'],
                  hAxis: {
                    'title': 'Normalized values',
                    titleTextStyle: {italic: false, bold: true}
                  },
                  vAxis: 
                    {title: 'Count', titleTextStyle: {italic: false, bold: true}},
                  
                }).setChartType('ColumnChart');

print(chart3);

Complete code can be accessed here. After running it in GEE code editor (it only takes a few seconds), I got following result.

enter image description here

First chart (blue) was obtained with ui.Chart.image.histogram for first image in collection (your histo image was not useful for getting histogram for entire collection and it cannot be added to Map Canvas). Only works with a scale higher than 35 meters (however, B2 bands have a scale of 10 meters). Second and third charts (red) are showing for, respectively, first image and entire collection. Both were obtained with ui.Chart.array.values.