1

This is throwing me for a loop, yet it seems so simple. I have two FeatureCollections that have the same features (but different properties), as they were generated by reducing over the same ImageCollection. I would like to combine the properties of these two FeatureCollections into a single FeatureCollection for export.

Here is a dummy script I put together--I'm using the Python API and my actual use case is quite involved, so I'm just showing this simple case.

I have tried an inner join (returns 4 features rather than just two), and a merge() (also return 4 features instead of two)--both are shown in the example code. Neither produces the expected output: a FeatureCollection with two features (defined by the image ids) and two properties ('date', and 'npix').

I am guessing that one likely answer is to combine the mapped functions into a single function and return a feature that contains all the properties I want to combine, but my workflow is quite involved at this point and it would be much simpler if I could just join the FeatureCollections.

Here is a code snippet to illustrate where I am stuck:

var start_date = '2010-01-01';
var end_date = '2019-01-01';
var scale = 30;

var feat = test_rois.first()

// Filter sensor collection by date and region
L8 = L8.filterDate(start_date, end_date).filterBounds(feat.geometry());
L8 = ee.ImageCollection(L8.toList(2)) // only keep two images for testing

// Dummy function for getting image dates as features
var dateadd = function(image){
  var date = image.date().format('YYYY-MM-dd');
  return ee.Feature(null, {'date':date})
}

// Dummy function for computing total number of pixels within polygon
var n_total = function(img) {
  var npix = img.select('B1').reduceRegion({
  reducer: ee.Reducer.count(),
  geometry: feat.geometry(),
  scale: scale,
  });
  return ee.Feature(null, {'npix':npix.get('B1')})
};

// Map over the ImageCollection
var date_fc = L8.map(dateadd);
var npix_fc = L8.map(n_total);

// Look at results
print('Date Featurecollection', date_fc)
print('Npix Featurecollection', npix_fc)

// Attempt a join
var toyFilter = ee.Filter.equals({
  leftField: 'id',
  rightField: 'id',
});

var innerJoin = ee.Join.inner('primary', 'secondary');
var toyJoin = innerJoin.apply(date_fc, npix_fc, toyFilter);
print('Inner join toy example:', toyJoin);

// Attempt a merge
var merged = ee.FeatureCollection(date_fc).merge(npix_fc)
print('Merged:', merged)
1

The inner join looks for properties in your features but id is not set in properties. So what we can do is add a new property id to the features.

// Dummy function for getting image dates as features
var dateadd = function(image){
  var date = image.date().format('YYYY-MM-dd');
  return ee.Feature(null, {'date':date,'id':image.id()})
}

// Dummy function for computing total number of pixels within polygon
var n_total = function(img) {
  var npix = img.select('B1').reduceRegion({
  reducer: ee.Reducer.count(),
  geometry: feat.geometry(),
  scale: scale,
  });
  return ee.Feature(null, {'npix':npix.get('B1'),'id':img.id()})
};

After you do join it will give you a feature with two matching features based on your condition, which in this case is 'id', in two properties that you defined. So you can clean the result of join by taking one feature, say the one in primary, and copy over the properties of feature from secondary.

function cleanJoin(feature){
  return ee.Feature(feature.get('primary')).copyProperties(feature.get('secondary'));
}
print(toyJoin.map(cleanJoin));

Edit: Or as @RodrigoE.Principe mentioned below, you can use system:index to access your feature ids so all you'd have to change is the filter that is used on join to

// Attempt a join
var toyFilter = ee.Filter.equals({
  leftField: 'system:index',
  rightField: 'system:index',
});
  • 2
    I think you could avoid the first step of adding an id by just using system:index property – Rodrigo E. Principe Jul 4 at 10:37
  • @RodrigoE.Principe Tank you for reminding me that. i will update my answer with that solution as well. – Nishanta Khanal Jul 5 at 3:42
  • Thank, you, but I forgot to mention that I got this far once, but when I export it I just get <Feature> rather than the actual value in the CSV. Please see the updated question. Sorry, I don't mean to "move the goalposts" but I assumed any answer would be exportable. I think that probably I need to create a new FeatureCollection and select the properties I want? The trouble is that I have many properties to add! – Jon Jul 8 at 19:12
  • That would undoubtedly be the case if you exported after joining. That is one of the reasons why you'd need to run the "clean join" step that i've mentioned. Can you try running that step and then exporting? exportColl = toyJoin.map(cleanJoin) then you just export the exportColl – Nishanta Khanal Jul 9 at 9:21
  • Derp, I completely skipped over your cleanJoin code! I don't know how I missed it...I will try it. – Jon Jul 9 at 16:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.