Cliente y servidor

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

Consulta la página Entorno de Python para obtener información sobre la API de Python y el uso de geemap para el desarrollo interactivo.

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

Consulta la página Entorno de Python para obtener información sobre la API de Python y el uso de geemap para el desarrollo interactivo.

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

Consulta la página Entorno de Python para obtener información sobre la API de Python y el uso de geemap para el desarrollo interactivo.

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!")

Consulta la página Entorno de Python para obtener información sobre la API de Python y el uso de geemap para el desarrollo interactivo.

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?

Consulta la página Entorno de Python para obtener información sobre la API de Python y el uso de geemap para el desarrollo interactivo.

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);

Consulta la página Entorno de Python para obtener información sobre la API de Python y el uso de geemap para el desarrollo interactivo.

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);

Consulta la página Entorno de Python para obtener información sobre la API de Python y el uso de geemap para el desarrollo interactivo.

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.

(Consulta la sección sobre las funciones del cliente y del servidor para obtener una descripción de las funciones que se ejecutan en el cliente).

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);

Consulta la página Entorno de Python para obtener información sobre la API de Python y el uso de geemap para el desarrollo interactivo.

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

Consulta la página Entorno de Python para obtener información sobre la API de Python y el uso de geemap para el desarrollo interactivo.

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!

Consulta la página Entorno de Python para obtener información sobre la API de Python y el uso de geemap para el desarrollo interactivo.

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!

Consulta la página Entorno de Python para obtener información sobre la API de Python y el uso de geemap para el desarrollo interactivo.

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().