Saturday, 9 January 2016

Converting .map() from JavaScript API to Python API?


I wrote this code using the Earth Engine JavaScript API. The code clips the image collection using variable "table," which is a feature collection of about 12,000 points. I get the length of the image collection and use that number to create a a variable "sequence." I use this variable to create a nested map loop of sorts. I grab a single image and get a list of coordinates from that image. Then for each set of coordinates in the list, I store a bunch of information from that point into a dictionary and create a feature out of it. I need to convert this code to Python, but I am not sure how to convert the lines of code that use the map() function twice ("var getImgCoords and var getMetadata"). The variable "sequence2" changes for each loop, so I thought I could use the iterate() function instead of map().


var TerraClimate = ee.ImageCollection("IDAHO_EPSCOR/TERRACLIMATE"),

var table = ee.FeatureCollection("users/adrianom/CAN_AK_Coordinates")

var SearchArea = table;
var SearchAreaGeom = SearchArea.geometry();
var terraclimate_bounds = TerraClimate.filterBounds(SearchAreaGeom);

// Clip collection to search area, more precisely than filterBounds above.
var icClip = terraclimate_bounds.map(function(img){
var i = img.clip(SearchAreaGeom);
return(i);

});

var icClip_len = icClip.size();
var col_list = icClip.toList(icClip_len);


var sequence = ee.List.sequence(0, icClip_len.subtract(1));


var getImgCoords = sequence.map(function(i){

var img = ee.Image(col_list.get(i));
var coords = img.geometry().coordinates();
var coords_len = coords.size();
var sequence2 = ee.List.sequence(0, coords_len.subtract(1));

var getMetadata = sequence2.map(function(j){
var coor = coords.get(j);
var geom = ee.Geometry.Point(coor);
var reduce = img.reduceRegion(ee.Reducer.mean(), geom, 4638.312116386398);


var dictionary = ee.Dictionary({
x: ee.List(coor).get(0),
y: ee.List(coor).get(1),
Start_Date: ee.Date(img.get('system:time_start')),
End_Date: ee.Date(img.get('system:time_end'))
});

var combine_dict = reduce.combine(dictionary);
var feature = ee.Feature(geom, combine_dict);
return(feature);

});


return(getMetadata);

});

Answer



This is an interesting question, since you shouldn't need to change anything to migrate from JS to Python, but in this case where you have a nested loop you have to do some workaround. No need to change the logic, just the structure.


import ee
ee.Initialize()


TerraClimate = ee.ImageCollection("IDAHO_EPSCOR/TERRACLIMATE")
table = ee.FeatureCollection("users/adrianom/CAN_AK_Coordinates")

SearchArea = table
SearchAreaGeom = SearchArea.geometry()
terraclimate_bounds = TerraClimate.filterBounds(SearchAreaGeom)

# Clip collection to search area, more precisely than filterBounds above.
icClip = terraclimate_bounds.map(lambda img: img.clip(SearchAreaGeom))


icClip_len = icClip.size()
col_list = icClip.toList(icClip_len)
sequence = ee.List.sequence(0, icClip_len.subtract(1))

# make a function that takes coords and img and return a function
def getMetadata(coords, img):
# I changed coords because did not work as you have it in JS
coords = ee.List(ee.List(coords).get(0))
img = ee.Image(img)

def wrap(j):
coor = ee.List(coords.get(j))
geom = ee.Geometry.Point(coor)
reduce = img.reduceRegion(ee.Reducer.mean(), geom, 4638.312116386398)

dictionary = ee.Dictionary({
'x': ee.List(coor).get(0),
'y': ee.List(coor).get(1),
'Start_Date': ee.Date(img.get('system:time_start')),
'End_Date': ee.Date(img.get('system:time_end'))

})

combine_dict = reduce.combine(dictionary)
feature = ee.Feature(geom, combine_dict)
return feature
return coor
return wrap

# function to loop over image indexes
def getImgCoords(i):

img = ee.Image(col_list.get(i))
coords = img.geometry().coordinates()
coords_len = coords.size()
sequence2 = ee.List.sequence(0, coords_len.subtract(1))
# the function getMetadata returns a function, so map it
return sequence2.map(getMetadata(coords, img))

# final result
imgCoords = sequence.map(getImgCoords)


By the way, you don't need to map over a list of indexes and get the elements from the list with the given index.. the map function goes over each element of the list, so you should just use it that way. In getImgCoords just map over coords and instead o mapping over sequence you could just map over col_list. But I translated the code as it was.


No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...