1

I am trying to write a function which will create a dictionary from an image collection using Sentinel 2 data which will contain label/value pairs where the label comes from the MGRS_TILE property of the image and the value will contain a list of all the images with the same MGRS_TILE id. The label values must be distinct.I want the output to be like this: {'label' : 'tileid1', 'values':[ image1, image2 ...] 'label' : 'tileid2', 'values':[ image3, image4 ...]}

Below is my code: interestImageCollection is my filtered imageCollection object tileIDS is a ee.List type object containg all of the distinct tile ids and field is the name of the image property of my interest which in this case is 'MGRS_TILE'.

var build_selectZT = function(interestImageCollection, tileIDS, field){

  //this line returns a list which contains the unique tile ids thanks to the keys function
  //var field_list = ee.Dictionary(interestImageCollection.aggregate_histogram(field)).keys();

  //.map must always return something
  var a = tileIDS.map(function(tileId) {
    var partialList=ee.List([]);
    var partialImage = interestImageCollection.map(function(image){
      return ee.Algorithms.If(ee.Image(image).get(field)==tileId, image, null);
    });
    partialList.add(partialImage);
    return ee.Dictionary({'label': tileId, 'value': partialList});
  }).getInfo();
  return a;
};

Unfortunately the above function gives me this result: {'label' : 'tileid1', 'values':[], 'label' : 'tileid2', 'values':[]}

1 Answers1

0

I think you can use filter function instead of using if. And if you need it in list form then you could change it to list using toList function.

var build_selectZT = function(interestImageCollection, tileIDS, field){
  //.map must always return something
  var a = tileIDS.map(function(tileId) {
    var partialList=ee.List([]);
    // get subset of image collection where images have specific tileId
    var subsetCollection = interestImageCollection.filter(ee.Filter.eq(field, tileId));
    // convert the collection to list
    var partialImage = subsetCollection.toList(subsetCollection.size())
    partialList.add(partialImage);
    return ee.Dictionary({'label': tileId, 'value': partialList});
  }).getInfo();
  return a;
};

BUT this would actually give you a list of dictionaries

[{'label':'id1','value':[image1]},{'label':'id2','value':[image2,image3]......}]

If you want to use ee.Algorithms.If like you did in your code then your error is in the "ee.Image(image).get(field)==tileId" part. as .get(field) is returning a server side object, you can't use == to equate it to something, since it is an string type you need to use compareTo instead. However, it returns 0 if the strings are same and since 0 is treated as false, you can return image when condition is false.

return ee.Algorithms.If(ee.String(ee.Image(image).get(field)).compareTo(tileId), null, image);

I still think this is a bad way as you'll get an array full of null in values like

[{'label':'id1','value':[image1, null, null, null, .....]},{'label':'id2','value':[null,image2,image3, null,....]......}]
Nishanta Khanal
  • 316
  • 2
  • 4
  • Thank you very much for your response. Your code was very helpful and your advices for the ee.Algorithm.If on point. I just removed the var partialList=ee.List([]); , substituted the filter with the filterMetaData function and added the partialImage variable as the value in the Dictionary and it worked like a charm! – Lazaros Stam Jul 24 '19 at 08:05
  • Also I know this was not part of the original question but do you know how can I set dynamic key values? I want to set the key value to be that of the tileid's value but simply typing ee.Dictionary({ tileId : partialImage}); stores 'tileid' as the key. – Lazaros Stam Jul 24 '19 at 09:17
  • found it: return ee.Dictionary({}).set(tileId,partialImage); seems to work perfectly. – Lazaros Stam Jul 24 '19 at 09:49