2

I am a pretty new user to Earth Engine, and I am trying to map over a list in order to use the numbers inside as indices. As a quick example, in R this would be

for (i in 1:10){print i}

In Earth Engine, doing this separately works beautifully. Here, "points" is a FeatureCollection made up of 10 points, and my goal is to filter the "l8sr" ImageCollection to only give me the images that pertain to point #2. Then, I get mean NDVI for the time series.

var coords = points.geometry().coordinates()
  print('coords', coords)

  var onepoint = ee.Geometry.Point(coords.get(2)) //for example
  print(onepoint)

  var test = l8sr.filterBounds(onepoint)
  print('test', test)
  print(ui.Chart.image.series(test, onepoint, ee.Reducer.mean(), 30))

BUT, when I try to map this over all 10 points in "coords", I get a list of 10 empty ImageCollections (I can't print to a chart because these are undefined). Why is this?

Here is reproducible code:

// Make a list of Features.
var features = [
  ee.Feature(ee.Geometry.Point(97.58, 24.36), {name: 'sample1'}),
  ee.Feature(ee.Geometry.Point(99.45, 20.26), {name: 'sample2'}),
  ee.Feature(ee.Geometry.Point(93.24, 21.42), {name: 'sample3'}),
  ee.Feature(ee.Geometry.Point(96.13, 24.12), {name: 'sample4'}),
  ee.Feature(ee.Geometry.Point(96.88, 22.48), {name: 'sample5'})
];

// Create a FeatureCollection from the list and print it.
var points = ee.FeatureCollection(features);
print(points);

var l8sr = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR')
                  .filterDate('2015-06-23', '2020-01-31')
                  .filterBounds(points)
print("Landsat", l8sr)

//this works (down to /$/$)
var coords = points.geometry().coordinates()
print('coords', coords)

var onepoint = ee.Geometry.Point(coords.get(2))
print(onepoint)

var newt = l8sr.filterBounds(onepoint)
print('newt', newt)
print(ui.Chart.image.series(newt, onepoint, ee.Reducer.mean(), 30))

// /$/$ /////////////

// this doesn't work
var ser = ee.List.sequence(0,4)
print(ser)

var test1 = ser.map(function(q){
  var sub = l8sr.filterBounds(ee.Geometry.Point(coords.get(q)))
  return sub
  //return ui.Chart.image.series(sub, point_a, ee.Reducer.mean(), 30)
})

// test1 is a list of ImageCollections, but each one has no actual bands.
print(test1)
2
  • 1
    Your script link doesn't work for us because the asset it uses isn't shared. Also, it will be easier to answer your question, and more helpful for other people, if your code is not the entire thing you're working on, but just enough to demonstrate the problem — it doesn't matter if it doesn't compute anything meaningful. Once you've created this short code, please edit it into your question as well as providing a link.
    – Kevin Reid
    Apr 8 '20 at 23:15
  • Sorry my bad, I've updated the code using example points. I thought the share thing would work.
    – waiiana
    Apr 9 '20 at 1:22
1

There are two things going on here.

First, the bands: [] does not mean that the images have no bands. Try print(ee.ImageCollection('LANDSAT/LC08/C01/T1_SR').limit(10)) — you'll see that even just listing the original unedited collection, bands is empty. So, that's only misleading — it has nothing to do with the contents of the collection.

The bands list for a collection only has contents in a special case when information is known about the type of all bands in all images in the collection. I'm not actually sure when that happens, but it's not guaranteed in general.


What's actually missing here, compared to the usual situation, is the features field which would list the images. Note that the console says "ImageCollection (unknown elements)", not "ImageCollection (0 elements)".

This is because, in general, the contents of feature or image collections are handled specially — they don't exist, in a sense, until they're requested. This allows efficient use of operations like filtering a collection (because Earth Engine does not have to fetch the entire collection from storage to run the filter on it), but it means that listing a collection is a special operation.

When you request a value from the Earth Engine service (as print does internally), there is a special case where, if the value is a collection, its contents will be retrieved and included in the response. But in your case, the value isn't a collection, it's a list of collections, so that special case does not apply.


Your image collections are working fine. Their contents may not show up in print(), but if you use them in further computation it will work as you expect.

As a quick demonstration, you can try this:

print(ee.FeatureCollection(test1).flatten());

This will turn your list of ImageCollections into a single ImageCollection, and its contents will show up in print.


However, because in this particular case you want to display a chart, which is a client-side object, you need to do something different there — you need to skip ee.List.sequence entirely and use regular JavaScript, to display multiple charts. Like so (editing your example):

for (var i = 0; i < features.length; i++) {
  var coll = test1.get(i); 
  print(ui.Chart.image.series(coll, points, ee.Reducer.mean(), 30));
}

This has nothing to do with the above issues; rather, you must always use client-side code to produce multiple charts or other UI elements.

5
  • Ah this makes sense, thank you! I tried doing print(test1.get(1)) and it definitely worked. How come, then, if I want to print a chart for each element of this list, this code doesn't work? var test2 = ser.map(function(w){var coll = test1.get(w); var chart = ui.Chart.image.series(coll, points, ee.Reducer.mean(), 30); return chart}); print(test2)
    – waiiana
    Apr 9 '20 at 12:13
  • @waiiana That's actually a completely different thing — it's not anything to do with the collections, but that you can't build a chart inside a server-side map operation and you have to use an actual loop. I've updated my answer to cover that.
    – Kevin Reid
    Apr 9 '20 at 15:21
  • ah I didn't realize I had to go back to normal JS. Thank you! Sorry, but one last thing is that when I ran this for loop in my test script, I got "feature" is not defined in this scope. I tried changing it to test1 and test1.get(i) but it did not work. Do you know why? Also apologies I'm trying to do the @ your name but when I post the comment it disappears.
    – waiiana
    Apr 9 '20 at 15:37
  • @waiiana The @ disappears because the author of a post is always notified, so it's redundant. If you're seeing ' "feature" is not defined in this scope ' then you have a typo somewhere because the code I wrote should be referring to "features" (plural), the list you defined at the top of your script. Whenever you get a not defined error, always check for where in your script that exact name is or isn't mentioned, using the find function.
    – Kevin Reid
    Apr 9 '20 at 16:22
  • Gotcha, yep that was my bad with too many tabs. Thank you so much for your help!
    – waiiana
    Apr 9 '20 at 17:50

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.