Google Earth Engine – Setting system:id Property with Function in Python API

google-earth-enginegoogle-earth-engine-python-api

I want to change the system:id of images in an image collection based on the system:index. I can do this in the javascript api like this:

//read in image collection
var l8 = ee.ImageCollection("LANDSAT/LC08/C02/T1_TOA");

//get first two images
var first_two = l8.limit(2)

//print system:index with slice for first image
var idx = ee.String(first_two.first().get('system:index')).slice(0,4)

print(idx)

//set system id with function
var repls = function(feature){
  var sub =  ee.String(feature.get('system:index')).slice(0,4);
  return(feature.set('system:id', sub))
};


//apply function
first_two = first_two.map(repls)

print(first_two)

Here is a runnable script:

https://code.earthengine.google.com/7452dbd8307d04ab17e4dc262b0554c2

This works just fine, but I want to do the same thing in python. I am doing it like this:

#read in image collection
l8 = ee.ImageCollection("LANDSAT/LC08/C02/T1_TOA")

#get first two images
first_two = l8.limit(2)

#print system:index with slice for first one
idx = str(first_two.first().get('system:index').getInfo())[0:4]

print(idx)

#set system id in loop
def repls(feature):
  sub = feature.get('system:index').getInfo()[0:4]
  return feature.set('system:id', sub)

#map the function
l8 = l8.map(repls)

print(l8)

but this fails with:

EEException: A mapped function's arguments cannot be used in client-side operations

This only fails when applying the function to an image collection. For instance, I have no problem in python doing this to a single image:

l8 = ee.ImageCollection("LANDSAT/LC08/C02/T1_TOA")
    
first = l8.first()
    
#print system:index with slice
idx = str(first.get('system:index').getInfo())[0:4]
    
print(idx)
    
#set system id
first = first.set('system:id', idx)
    
print(first.get('system:id').getInfo())

Best Answer

getInfo() is a client-side operation and cannot be used in map(). Likewise, Python list subsetting [0:4] cannot be used inside map() either.

Instead, you can use the server-side slice to substring the 'system:index', just like you do in javascript:

#set system id in loop
def repls(feature):
  # cast the 'system:index' as an ee.String and slice the first 4 characters
  sub = ee.String(feature.get('system:index')).slice(0,4)
  return feature.set('system:id', sub)

#map the function
l8 = l8.map(repls)

# printing the whole collection resulted in too many elements, so print the first image
print(l8.first().getInfo())