Клиентские библиотеки Earth Engine для Python и JavaScript преобразуют сложный геопространственный анализ в запросы Earth Engine. Код, который вы пишете для клиентской библиотеки, может содержать смесь ссылок на объекты на стороне клиента и переменные, представляющие объекты на стороне сервера.
Важно отличать объекты Earth Engine от других объектов или примитивов Python или JavaScript, которые могут быть в вашем коде. Вы можете манипулировать объектами на сервере, манипулируя объектами «прокси» на стороне клиента в вашем сценарии. Вы можете распознать прокси-объект как что угодно, начинающееся с ee
. Эти прокси-объекты Earth Engine не содержат никаких фактических данных и представляют собой просто дескрипторы объектов на сервере. Для начала рассмотрим строковый объект на стороне клиента (который НЕ является прокси-объектом):
Редактор кода (JavaScript)
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
Из выходных данных обратите внимание, что клиент (веб-браузер или блокнот) интерпретировал этот код и запустил его, определив, что переменная имеет тип string
. Теперь предположим, что вы хотите, чтобы Earth Engine мог что-то делать с этой строкой. Для этого вам нужно поместить строку в красивый контейнер и отправить ее в Google. Этот контейнер является прокси-объектом. Вот пример:
Редактор кода (JavaScript)
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
Обратите внимание на вывод, что ee.String
является object
, а НЕ string
. Точнее, это ee.computedObject
, что означает, что это прокси-объект для чего-то на сервере. Думайте о ee.Thing
как о способе поместить вещь в контейнер для отправки в Google. Ваш клиент не знает, что находится в контейнере, но вы можете узнать, что в нем, распечатав это:
Редактор кода (JavaScript)
print(serverString); // I am not a String
import ee import geemap.core as geemap
Колаб (Питон)
print(server_string.getInfo()) # I am not a String
Чтобы увидеть, как выглядит сам контейнер, напечатайте строковое представление объекта:
Редактор кода (JavaScript)
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!"})
Если по какой-то причине вам нужно использовать Python или JavaScript, работающий в клиенте, для управления всем, что находится в контейнере, используйте getInfo()
чтобы получить содержимое контейнера и присвоить его переменной:
Редактор кода (JavaScript)
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?
Зацикливание
Поскольку клиент не знает, что находится в объектах ee.Thing
на стороне сервера, операции на стороне клиента, такие как условные выражения и циклы for, с ними не работают. По этой причине и во избежание синхронных вызовов getInfo()
используйте серверные функции, насколько это возможно. Например, рассмотрим следующие два способа создания списка:
Не рекомендуется — цикл for на стороне клиента
Редактор кода (JavaScript)
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)
Рекомендуется — сопоставление на стороне сервера.
Редактор кода (JavaScript)
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())
Пример сопоставления на стороне сервера немного глуп, потому что тот же список можно создать просто с помощью ee.List.sequence(1, 8)
, но он иллюстрирует некоторые важные концепции. Первая концепция — это map()
, которая просто применяет одну и ту же функцию ко всему в списке. Поскольку эта функция выполняется на сервере, клиентские функции, такие как getInfo()
и print()
не будут работать в сопоставленной функции. По этой причине код i + 1
необходимо заменить эквивалентным кодом на стороне сервера: ee.Number(n).add(1)
. Важно отметить, что n
— это объект, который существует только на сервере. Поскольку функция не знает тип своего аргумента, его необходимо привести к ee.Number
.
Также стоит отметить, что иногда функциональность на стороне клиента оказывается удобной. Например, предыдущий цикл for можно использовать для создания списка и обертывания его серверным объектом:
Редактор кода (JavaScript)
var toServerList = ee.List(clientList);
import ee import geemap.core as geemap
Колаб (Питон)
to_server_list = ee.List(client_list)
Помните, что обработка на стороне клиента выполняется в вашем ноутбуке или браузере, в процессоре хост-компьютера, поэтому она может быть менее эффективной, чем использование Earth Engine для выполнения работы на сервере. Кроме того, чтобы избежать потенциально неожиданных результатов, рекомендуется избегать смешивания функций клиента и сервера в ваших сценариях. В разделе «Условия» приведен пример возможных непредвиденных последствий.
Условные предложения
Объекты на стороне сервера не обязательно работают с функциями на стороне клиента, и наоборот. Например, рассмотрим случай логической переменной на стороне сервера:
Редактор кода (JavaScript)
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
Как показано в следующем примере, переменная не ведет себя в условном выражении на стороне клиента, поскольку это объект на стороне сервера. Чтобы правильно проверить логическое значение на стороне сервера, используйте функцию на стороне сервера:
Не рекомендуется — условно на стороне клиента
Редактор кода (JavaScript)
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!
Рекомендуется — условно на стороне сервера
Редактор кода (JavaScript)
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!
Функции клиента и сервера
В предыдущих разделах описано несколько причин, по которым неэффективно или нелогично смешивать клиентские и серверные объекты и функции. Какие объекты и функции являются клиентскими, а какие — серверными? В общем, все, что инициализируется как ee.Thing
является серверным объектом, а любой метод этого объекта, ee.Thing.method()
, является серверной функцией. Объекты и функции, которые появляются в справочнике по Python или JavaScript, являются клиентскими. Как отмечалось ранее, вы можете использовать функции на стороне клиента для создания объекта, а затем обернуть его, передав объект на стороне клиента конструктору Earth Engine, например ee.String()
.