Las bibliotecas cliente de Earth Engine para Python y JavaScript traducen análisis geoespaciales complejos en solicitudes de Earth Engine. El código que escribes para una biblioteca cliente puede contener una combinación de referencias a objetos y variables del cliente que representan objetos del servidor.
Es importante distinguir los objetos de Earth Engine de otros objetos o primitivos de Python o JavaScript que puedan estar en tu código. Puedes manipular objetos en el servidor manipulando los objetos "proxy" del cliente en tu secuencia de comandos. Puedes reconocer un objeto proxy como cualquier elemento que comience con ee
. Estos objetos de proxy de Earth Engine no contienen datos reales y son solo identificadores de objetos en el servidor. Para comenzar, considera un objeto de cadena del cliente (que NO es un objeto de proxy):
var clientString = 'I am a String'; print(typeof clientString); // string
import ee import geemap.core as geemap
client_string = 'I am a String' print(type(client_string)) # str
Observa en el resultado que el cliente (el navegador web o la notebook) interpretó este código y lo ejecutó, y determinó que la variable es del tipo string
. Ahora supongamos que quieres que Earth Engine pueda hacer algo con esta cadena. Para ello, debes unir la cadena en un contenedor ordenado
y enviarla a Google. Ese contenedor es el objeto proxy. Por ejemplo:
var serverString = ee.String('I am not a String!'); print(typeof serverString); // object print('Is this an EE object?', serverString instanceof ee.ComputedObject); // true
import ee import geemap.core as geemap
server_string = ee.String('I am not a String!') print(type(server_string)) # ee.ee_string.String print( 'Is this an EE object?', isinstance(server_string, ee.ee_string.String) ) # True
Observa en el resultado que ee.String
es object
,
NO string
. Más específicamente, es un ee.computedObject
, lo que significa que es un objeto proxy para algo en el servidor. Piensa en ee.Thing
como
la forma de colocar un elemento en un contenedor para enviarlo a Google. Tu cliente no sabe qué hay en el contenedor, pero puedes averiguarlo si lo imprimes:
print(serverString); // I am not a String
import ee import geemap.core as geemap
print(server_string.getInfo()) # I am not a String
Para ver cómo se ve el contenedor, imprime la representación de cadena del objeto:
print(serverString.toString()); // ee.String("I am not a String!")
import ee import geemap.core as geemap
print(server_string) # ee.String({"constantValue": "I am not a String!"})
Si, por algún motivo, necesitas usar Python o JavaScript
en ejecución en el cliente para manipular lo que está en el contenedor, usa
getInfo()
para obtener el contenido del contenedor y asignarlo a una variable:
var someString = serverString.getInfo(); var strings = someString + ' Am I?'; print(strings); // I am not a String! Am I?
import ee import geemap.core as geemap
some_string = server_string.getInfo() strings = some_string + ' Am I?' print(strings) # I am not a String! Am I?
Repetición
Debido a que el cliente no sabe qué contiene los objetos ee.Thing
del servidor, las operaciones del cliente, como las condicionales y los bucles for, no funcionan con ellos. Por
ese motivo, y para evitar llamadas síncronas a getInfo()
, usa funciones
del servidor en la medida de lo posible. Por ejemplo, considera las siguientes dos formas de crear una lista:
No se recomienda: bucle for del cliente
var clientList = []; for(var i = 0; i < 8; i++) { clientList.push(i + 1); } print(clientList);
import ee import geemap.core as geemap
client_list = [] for i in range(8): client_list.append(i + 1) print(client_list)
Recomendado: Asignación del servidor
var serverList = ee.List.sequence(0, 7); serverList = serverList.map(function(n) { return ee.Number(n).add(1); }); print(serverList);
import ee import geemap.core as geemap
server_list = ee.List.sequence(0, 7) server_list = server_list.map(lambda n: ee.Number(n).add(1)) print(server_list.getInfo())
El ejemplo de asignación del servidor es un poco porque podrías hacer la misma lista solo con ee.List.sequence(1, 8)
, pero ilustra algunos conceptos importantes. El primer concepto es map()
, que simplemente aplica la misma función a todo lo que está en la lista. Debido a que esta función se ejecuta en el servidor, las funciones del cliente, como getInfo()
y print()
, no funcionarán en una función asignada. Por esa razón, el código i + 1
debe reemplazarse por el código del servidor equivalente: ee.Number(n).add(1)
. Es importante tener en cuenta que n
es un objeto que solo existe en el servidor. Como la función no conoce el tipo de su argumento, se debe transmitir a un ee.Number
.
También es importante tener en cuenta que, en ocasiones, la funcionalidad del cliente es conveniente. Por ejemplo, el bucle for anterior se podría usar para crear una lista y unirla con un objeto del servidor:
var toServerList = ee.List(clientList);
import ee import geemap.core as geemap
to_server_list = ee.List(client_list)
Ten en cuenta que el procesamiento del cliente se realiza en tu notebook o navegador, la CPU de la máquina anfitrión, por lo que puede ser menos eficiente que usar Earth Engine para realizar el trabajo en el servidor. Además, para evitar resultados potencialmente sorprendentes, se recomienda evitar mezclar la funcionalidad del cliente y del servidor en tus secuencias de comandos. En la sección Condicionales, se proporciona un ejemplo de consecuencias posiblemente no deseadas.
Condicionales
Los objetos del servidor no necesariamente funcionan con funciones del cliente y viceversa. Por ejemplo, considera el caso de una variable booleana del servidor:
var myList = ee.List([1, 2, 3]); var serverBoolean = myList.contains(5); print(serverBoolean); // false
import ee import geemap.core as geemap
my_list = ee.List([1, 2, 3]) server_boolean = my_list.contains(5) print(server_boolean.getInfo()) # False
Como se muestra en el siguiente ejemplo, la variable no se comporta en una sentencia condicional del cliente porque es un objeto del servidor. Para verificar correctamente un valor booleano del servidor, usa una función del servidor:
No se recomienda: Condicional del cliente
var clientConditional; if (serverBoolean) { clientConditional = true; } else { clientConditional = false; } print('Should be false:', clientConditional); // True!
import ee import geemap.core as geemap
if server_boolean: client_conditional = True else: client_conditional = False print('Should be False:', client_conditional) # True!
Recomendado: Condicional del servidor
var serverConditional = ee.Algorithms.If(serverBoolean, 'True!', 'False!'); print('Should be false:', serverConditional); // False!
import ee import geemap.core as geemap
server_conditional = ee.Algorithms.If(server_boolean, 'True!', 'False!') print('Should be False:', server_conditional.getInfo()) # False!
Funciones del cliente y del servidor
En las secciones anteriores, se describen varios motivos por los que es ineficiente o ilógico mezclar objetos y funciones de cliente y servidor. ¿Qué objetos y funciones son del cliente y cuáles son del servidor? En general, todo lo que se inicializa como ee.Thing
es un objeto de servidor, y cualquier método en ese objeto, ee.Thing.method()
, es una función de servidor. Los objetos y las funciones que aparecen en la referencia de Python o JavaScript son del cliente. Como se señaló anteriormente, puedes usar la funcionalidad del cliente para crear un objeto y, luego, unirlo proporcionando el objeto del cliente a un constructor de Earth Engine, por ejemplo, ee.String()
.