Алгоритмы, которые вы создаете в Earth Engine, работают в облаке Google, распределенном по множеству компьютеров. Отладка может быть сложной задачей, поскольку ошибки могут возникать либо в коде на стороне клиента, либо при выполнении закодированных инструкций на стороне сервера и быть результатом проблем масштабирования, а также синтаксических или логических ошибок. Части программы, работающие где-то в облаке, недоступны для проверки, если вы их не попросите. В этом документе представлены стратегии, инструменты и решения отладки, которые помогут вам устранить распространенные ошибки и отладить сценарии Earth Engine.
Синтаксические ошибки
Синтаксические ошибки возникают, когда ваш код нарушает правила языка программирования (JavaScript или Python в Earth Engine). Эти ошибки препятствуют запуску вашего кода и обычно обнаруживаются перед выполнением. Если вы столкнулись с синтаксической ошибкой, внимательно просмотрите выделенную строку или сообщение об ошибке и обратитесь к таким ресурсам, как Справочник по языку Python или Руководство по стилю Google JavaScript . Линтер кода также может помочь выявить и устранить эти проблемы.
Ошибки на стороне клиента
Несмотря на синтаксически правильный код, могут быть ошибки, связанные с целостностью или логикой скрипта. Следующие примеры демонстрируют ошибки, возникающие из-за использования несуществующей переменной и метода.
Ошибка — этот код не работает!
Редактор кода (JavaScript)
// Load a Sentinel-2 image. var image = ee.Image('USGS/SRTMGL1_003'); // Error: "bandNames" is not defined in this scope. var display = image.visualize({bands: bandNames, min: 0, max: 9000}); // Error: image.selfAnalyze is not a function var silly = image.selfAnalyze();
import ee import geemap.core as geemap
Колаб (Питон)
# Load a Sentinel-2 image. image = ee.Image('USGS/SRTMGL1_003') # NameError: name 'band_names' is not defined. display = image.visualize(bands=band_names, min=0, max=9000) # AttributeError: 'Image' object has no attribute 'selfAnalyze'. silly = image.selfAnalyze()
Первая ошибка сообщает вам, что bandNames
не определена в области, в которой на нее ссылаются. В качестве решения установите переменную или укажите аргумент списка для параметра bands
. Вторая ошибка демонстрирует, что происходит при вызове несуществующей функции selfAnalyze()
. Поскольку это не настоящий метод для изображений, ошибка сообщает вам, что это не функция. В обоих случаях ошибка описывает проблему.
Приведение неизвестного типа объекта
Ошибка « ...is not a function
» может возникнуть из-за того, что Earth Engine не знает тип переменной. Общие проявления этой проблемы возникают в результате:
- Выполнение чего-либо с объектом, возвращаемым функцией
first()
(тип элементов коллекции неизвестен). - Выполнение чего-либо с объектом, возвращенным функцией
get()
(тип элемента, хранящегося в свойстве, неизвестен). - Выполнение чего-либо с аргументом функции (в самой функции), когда тип аргумента неизвестен.
Для примера первого:
Ошибка — этот код не работает!
Редактор кода (JavaScript)
var collection = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017'); // Error: collection.first(...).area is not a function var area = collection.first().area();
import ee import geemap.core as geemap
Колаб (Питон)
collection = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') # AttributeError: 'Element' object has no attribute 'area'. area = collection.first().area()
Решение во всех случаях — привести объект неизвестного типа к конструктору известного типа. Продолжая предыдущий пример, решение состоит в приведении к ee.Feature
:
Решение — используйте приведение!
Редактор кода (JavaScript)
var area = ee.Feature(collection.first()).area();
import ee import geemap.core as geemap
Колаб (Питон)
area = ee.Feature(collection.first()).area()
(Стоит отметить, что здесь вы можете безопасно вызывать любой метод Element
, потому что Earth Engine так считает).
Избегайте смешивания функций клиента и сервера.
Следующий пример менее очевиден:
Ошибка — этот код не делает то, что вы хотите
Редактор кода (JavaScript)
// Don't mix EE objects and JavaScript objects. var image = ee.Image('USGS/SRTMGL1_003'); var nonsense = image + 2; // You can print this, but it's not what you were hoping for. print(nonsense); // Error: g.eeObject.name is not a function Map.addLayer(nonsense);
import ee import geemap.core as geemap
Колаб (Питон)
# Don't mix EE objects and Python objects. image = ee.Image('USGS/SRTMGL1_003') nonsense = image + 2 # TypeError: unsupported operand type(s) for +: 'Image' and 'int'. display(nonsense) # TypeError: unsupported operand type(s) for +: 'Image' and 'int'. m = geemap.Map() m.add_layer(nonsense) m
Предположим, что автор этого кода намеревался добавить 2
к каждому пикселю изображения, это неправильный способ сделать это. В частности, этот код ошибочно смешивает объект на стороне сервера ( image
) с оператором на стороне клиента ( +
). Результаты могут оказаться неожиданными. В первом случае печать nonsense
в редакторе кода JavaScript выполнит запрошенную операцию ( +
), преобразуя image
и 2
в строки, а затем объединяя их. Результирующая строка является непредусмотренной (в Python выдается ошибка TypeError). Во втором случае, добавляя к карте nonsense
, загадочное g.eeObject.name is not a function
error отображается в редакторе кода JavaScript, поскольку объект, добавляемый на карту, nonsense
, является строкой, а не объектом EE (в Python выдается ошибка TypeError). Чтобы избежать возможных непредвиденных результатов и неинформативных ошибок, не смешивайте серверные объекты и функции с клиентскими объектами, примитивами или функциями. Решением в этом примере является использование функции сервера.
Решение — используйте серверную функцию!
Редактор кода (JavaScript)
Map.addLayer(image.add(2));
import ee import geemap.core as geemap
Колаб (Питон)
m = geemap.Map() m.add_layer(image.add(2)) m
Дополнительную информацию см. на странице «Клиент и сервер» .
Блокировка браузера редактора кода JavaScript
Зависание или блокировка браузера может произойти, если выполнение JavaScript в клиенте занимает слишком много времени или когда ожидается что-то от Earth Engine. Двумя распространенными источниками этой ошибки являются циклы for и/или getInfo()
в коде редактора кода JavaScript, причем в худшем случае getInfo()
находится внутри цикла for. Циклы for могут привести к блокировке браузера, поскольку код выполняется на вашем компьютере. С другой стороны, getInfo()
синхронно запрашивает результат вычисления у Earth Engine, блокируя его до тех пор, пока результат не будет получен. Если вычисление занимает много времени, блокировка может привести к блокировке вашего браузера. Избегайте циклов for и getInfo()
при работе в редакторе кода. Дополнительную информацию см. на странице «Клиент и сервер» .
Ошибки на стороне сервера
Несмотря на логическую последовательность в клиентском коде, могут быть ошибки, которые становятся очевидными только во время выполнения на сервере. Следующий пример демонстрирует, что происходит при попытке получить несуществующую группу.
Ошибка — этот код не работает!
Редактор кода (JavaScript)
// Load a Sentinel-2 image. var s2image = ee.Image( 'COPERNICUS/S2_HARMONIZED/20160625T100617_20160625T170310_T33UVR'); // Error: Image.select: Pattern 'nonBand' did not match any bands. print(s2image.select(['nonBand']));
import ee import geemap.core as geemap
Колаб (Питон)
# Load a Sentinel-2 image. s2image = ee.Image( 'COPERNICUS/S2_HARMONIZED/20160625T100617_20160625T170310_T33UVR' ) # EEException: Image.select: Band pattern 'non_band' did not match any bands. print(s2image.select(['non_band']).getInfo())
В этом примере ошибка сообщает вам, что нет полосы с именем nonBand
. Вероятно, очевидным решением является указание существующего названия группы. Вы можете узнать имена полос, распечатав изображение и просмотрев его в консоли, или распечатав список названий полос, возвращаемый image.bandNames()
.
Неизменяемость
Объекты на стороне сервера, которые вы создаете в Earth Engine, являются неизменяемыми . (Любой ee.Object
является Object
на стороне сервера). Это означает, что если вы хотите внести изменения в объект, вам придется сохранить измененное состояние в новой переменной. Например, это не поможет установить свойство изображения Sentinel-2:
Ошибка — этот код не делает то, что вы хотите!
Редактор кода (JavaScript)
var s2image = ee.Image( 'COPERNICUS/S2_HARMONIZED/20160625T100617_20160625T170310_T33UVR'); s2image.set('myProperty', 'This image is not assigned to a variable'); // This will not result in an error, but will not find 'myProperty'. print(s2image.get('myProperty')); // null
import ee import geemap.core as geemap
Колаб (Питон)
s2image = ee.Image( 'COPERNICUS/S2_HARMONIZED/20160625T100617_20160625T170310_T33UVR' ) s2image.set('my_property', 'This image is not assigned to a variable') # This will not result in an error, but will not find 'my_property'. display(s2image.get('my_property')) # None
В этом примере s2image.set()
возвращает копию изображения с новым свойством, но изображение, хранящееся в переменной s2image
, остается неизменным. Вам необходимо сохранить изображение, возвращаемое функцией s2image.set()
в новой переменной. Например:
Решение — зафиксируйте результат в переменной!
Редактор кода (JavaScript)
s2image = s2image.set('myProperty', 'OK'); print(s2image.get('myProperty')); // OK
import ee import geemap.core as geemap
Колаб (Питон)
s2image = s2image.set('my_property', 'OK') display(s2image.get('my_property')) # OK
Сопоставленные функции
Другой контекст, в котором функции клиента и сервера не смешиваются, — это сопоставленные функции. В частности, операции, указанные сопоставленной функцией, выполняются в облаке, поэтому клиентские функции, такие как getInfo
и Export
(а также print
и метод в Map
и Chart
в редакторе кода JavaScript), не будут работать в сопоставленных функциях. Например:
Ошибка — этот код не работает!
Редактор кода (JavaScript)
var collection = ee.ImageCollection('MODIS/006/MOD44B'); // Error: A mapped function's arguments cannot be used in client-side operations var badMap3 = collection.map(function(image) { print(image); return image; });
import ee import geemap.core as geemap
Колаб (Питон)
collection = ee.ImageCollection('MODIS/006/MOD44B') # Error: A mapped function's arguments cannot be used in client-side operations. bad_map_3 = collection.map(lambda image: print(image.getInfo()))
Эта несколько загадочная ошибка возникает в результате процесса, который Earth Engine использует для преобразования этого кода в набор инструкций, которые можно запускать на серверах Google. Клиентские функции и структуры управления нельзя использовать для работы с изображением аргумента, переданным отображаемой функции. Чтобы избежать этой ошибки, избегайте использования клиентских функций в сопоставленных функциях. См. страницу «Клиент и сервер», чтобы узнать больше о различиях между функциями клиента и сервера.
Сопоставленные функции имеют дополнительные требования. Например, сопоставленные функции должны что-то возвращать:
Ошибка — этот код не работает!
Редактор кода (JavaScript)
var collection = ee.ImageCollection('MODIS/006/MOD44B'); // Error: User-defined methods must return a value. var badMap1 = collection.map(function(image) { // Do nothing. });
import ee import geemap.core as geemap
Колаб (Питон)
collection = ee.ImageCollection('MODIS/006/MOD44B') # Error: User-defined methods must return a value. bad_map_1 = collection.map(lambda image: None)
Возможно, очевидное решение — вернуть что-то. Но он не может возвращать какие-либо вещи. В частности, функции, сопоставленные с ImageCollection
или FeatureCollection
должны возвращать Image
или Feature
. Например, вы не можете вернуть дату из функции, сопоставленной с ImageCollection
:
Ошибка — этот код не работает!
Редактор кода (JavaScript)
var collection = ee.ImageCollection('MODIS/006/MOD44B'); var badMap2 = collection.map(function(image) { return image.date(); }); // Error: Collection.map: A mapped algorithm must return a Feature or Image. print(badMap2);
import ee import geemap.core as geemap
Колаб (Питон)
collection = ee.ImageCollection('MODIS/006/MOD44B') bad_map_2 = collection.map(lambda image: image.date()) # EEException: Collection.map: # A mapped algorithm must return a Feature or Image. print(bad_map_2.getInfo())
Чтобы избежать этого, верните входное изображение с новым набором свойств. Затем, если вам нужен список дат изображений в коллекции, вы можете использоватьагрегат_array aggregate_array()
:
Решение — установить свойство!
Редактор кода (JavaScript)
var collection = ee.ImageCollection('MODIS/006/MOD44B'); var okMap2 = collection.map(function(image) { return image.set('date', image.date()); }); print(okMap2); // Get a list of the dates. var datesList = okMap2.aggregate_array('date'); print(datesList);
import ee import geemap.core as geemap
Колаб (Питон)
collection = ee.ImageCollection('MODIS/006/MOD44B') ok_map_2 = collection.map(lambda image: image.set('date', image.date())) print(ok_map_2.getInfo()) # Get a list of the dates. dates_list = ok_map_2.aggregate_array('date') print(dates_list.getInfo())
Процедурные ошибки
Узор был применен к изображению без полос.
Ошибка "Pattern 'my_band' was applied to an Image with no bands"
означает, что существует вызов ee.Image.select()
для изображения с пустым списком полос. Вот что вы можете сделать, чтобы решить эту проблему:
- Если изображение создается из ImageCollection с помощью редуктора или с использованием вызовов
first()
илиtoBands()
, убедитесь, что исходная коллекция не пуста. - Если изображение создается из словаря с помощью
ee.Dictionary().toImage()
, убедитесь, что словарь не пуст. - Если изображение является автономным, убедитесь, что оно содержит данные (а не просто
ee.Image(0)
).
Ошибки масштабирования
Хотя сценарий может быть синтаксически правильным, без логических ошибок и представлять собой допустимый набор инструкций для сервера, при распараллеливании и выполнении вычислений результирующие объекты могут быть слишком большими, слишком многочисленными или вычисление может занять слишком много времени. В этом случае вы получите сообщение об ошибке, указывающее, что алгоритм невозможно масштабировать. Эти ошибки, как правило, труднее всего диагностировать и устранять. Примеры ошибок такого типа:
- Тайм-аут вычислений истек
- Слишком много одновременных агрегатов
- Превышен лимит пользовательской памяти
- Произошла внутренняя ошибка
Улучшение масштабирования вашего кода позволит вам быстрее получать результаты, а также улучшить доступность вычислительных ресурсов для всех пользователей. Каждый тип ошибки обсуждается в следующих разделах, после чего вкратце упоминается reduceRegion()
, часто используемая функция, которая известна тем, что способна вызывать все типы ошибок масштабирования.
reduceRegion()
Несмотря на то, что reduceRegion()
жадно потребляет достаточное количество пикселей, чтобы вызвать множество разнообразных ошибок, существуют также параметры, предназначенные для управления вычислениями, поэтому вы можете преодолеть ошибки. Например, рассмотрим следующее нежелательное сокращение:
Ошибка — этот код не работает!
Редактор кода (JavaScript)
var absurdComputation = ee.Image(1).reduceRegion({ reducer: 'count', geometry: ee.Geometry.Rectangle([-180, -90, 180, 90], null, false), scale: 100, }); // Error: Image.reduceRegion: Too many pixels in the region. // Found 80300348117, but only 10000000 allowed. print(absurdComputation);
import ee import geemap.core as geemap
Колаб (Питон)
absurd_computation = ee.Image(1).reduceRegion( reducer='count', geometry=ee.Geometry.Rectangle([-180, -90, 180, 90], None, False), scale=100, ) # EEException: Image.reduceRegion: Too many pixels in the region. # Found 80300348117, but only 10000000 allowed. print(absurd_computation.getInfo())
Этот глупый пример просто для демонстрации. Цель этой ошибки — спросить вас, действительно ли вы хотите уменьшить 80300348117 (это 80 миллиардов ) пикселей. Если нет, увеличьте scale
(размер пикселя в метрах) соответствующим образом или установите bestEffort
значение true, чтобы автоматически пересчитать больший масштаб. Дополнительную информацию об этих параметрах см. на странице reduceRegion()
.
Тайм-аут вычислений истек
Предположим, вам нужны все эти пиксели для вычислений. Если да, вы можете увеличить параметр maxPixels
, чтобы обеспечить успешное вычисление. Однако Earth Engine потребуется некоторое время, чтобы завершить вычисления. В результате может возникнуть ошибка «тайм-аут вычислений»:
Плохо — не делай этого!
Редактор кода (JavaScript)
var ridiculousComputation = ee.Image(1).reduceRegion({ reducer: 'count', geometry: ee.Geometry.Rectangle([-180, -90, 180, 90], null, false), scale: 100, maxPixels: 1e11 }); // Error: Computation timed out. print(ridiculousComputation);
import ee import geemap.core as geemap
Колаб (Питон)
ridiculous_computation = ee.Image(1).reduceRegion( reducer='count', geometry=ee.Geometry.Rectangle([-180, -90, 180, 90], None, False), scale=100, maxPixels=int(1e11), ) # Error: Computation timed out. print(ridiculous_computation.getInfo())
Эта ошибка означает, что Earth Engine подождал около пяти минут, прежде чем остановить вычисления. Экспорт позволяет Earth Engine выполнять вычисления в среде с более длительным допустимым временем выполнения (но не с большим объемом памяти). Поскольку возвращаемое значение из reduceRegion()
является словарем, вы можете использовать словарь для установки свойств объекта с нулевой геометрией:
Хорошо — используйте Export
!
Редактор кода (JavaScript)
Export.table.toDrive({ collection: ee.FeatureCollection([ ee.Feature(null, ridiculousComputation) ]), description: 'ridiculousComputation', fileFormat: 'CSV' });
import ee import geemap.core as geemap
Колаб (Питон)
task = ee.batch.Export.table.toDrive( collection=ee.FeatureCollection([ee.Feature(None, ridiculous_computation)]), description='ridiculous_computation', fileFormat='CSV', ) # task.start()
Слишком много одновременных агрегатов
«Агрегационная» часть этой ошибки относится к операциям, которые распределены по нескольким машинам (например, сокращения, охватывающие более одной плитки). Earth Engine имеет ограничения, позволяющие предотвратить одновременный запуск слишком большого количества таких агрегатов. В этом примере ошибка «Слишком много одновременных агрегаций» вызвана сокращением карты:
Плохо — не делай этого!
Редактор кода (JavaScript)
var collection = ee.ImageCollection('LANDSAT/LT05/C02/T1') .filterBounds(ee.Geometry.Point([-123, 43])); var terribleAggregations = collection.map(function(image) { return image.set(image.reduceRegion({ reducer: 'mean', geometry: image.geometry(), scale: 30, maxPixels: 1e9 })); }); // Error: Quota exceeded: Too many concurrent aggregations. print(terribleAggregations);
import ee import geemap.core as geemap
Колаб (Питон)
collection = ee.ImageCollection('LANDSAT/LT05/C02/T1').filterBounds( ee.Geometry.Point([-123, 43]) ) def apply_mean_aggregation(image): return image.set( image.reduceRegion( reducer='mean', geometry=image.geometry(), scale=30, maxPixels=int(1e9), ) ) terrible_aggregations = collection.map(apply_mean_aggregation) # EEException: Computation timed out. print(terrible_aggregations.getInfo())
Предполагая, что целью этого кода является получение статистики изображений для каждого изображения, одним из возможных решений является Export
результата. Например, используя тот факт, что ImageCollection
также является FeatureCollection
, метаданные, связанные с изображениями, можно экспортировать в виде таблицы:
Хорошо — используйте Export
!
Редактор кода (JavaScript)
Export.table.toDrive({ collection: terribleAggregations, description: 'terribleAggregations', fileFormat: 'CSV' });
import ee import geemap.core as geemap
Колаб (Питон)
task = ee.batch.Export.table.toDrive( collection=terrible_aggregations, description='terrible_aggregations', fileFormat='CSV', ) # task.start()
Превышен лимит пользовательской памяти
Один из способов распараллеливания ваших алгоритмов в Earth Engine — это разделение входных данных на плитки, выполнение одних и тех же вычислений отдельно для каждой плитки, а затем объединение результатов. Как следствие, все входные данные, необходимые для вычисления выходного тайла, должны помещаться в память. Например, когда входными данными является изображение с множеством каналов, это может занять много памяти, если в вычислениях используются все каналы. Чтобы продемонстрировать, этот пример использует слишком много памяти, помещая (без необходимости) всю коллекцию изображений в плитку:
Плохо — не делай этого!
Редактор кода (JavaScript)
var bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7']; var memoryHog = ee.ImageCollection('LANDSAT/LT05/C02/T1').select(bands) .toArray() .arrayReduce(ee.Reducer.mean(), [0]) .arrayProject([1]) .arrayFlatten([bands]) .reduceRegion({ reducer: 'mean', geometry: ee.Geometry.Point([-122.27, 37.87]).buffer(1000), scale: 1, bestEffort: true, }); // Error: User memory limit exceeded. print(memoryHog);
import ee import geemap.core as geemap
Колаб (Питон)
bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'] memory_hog = ( ee.ImageCollection('LANDSAT/LT05/C02/T1') .select(bands) .toArray() .arrayReduce(ee.Reducer.mean(), [0]) .arrayProject([1]) .arrayFlatten([bands]) .reduceRegion( reducer=ee.Reducer.mean(), geometry=ee.Geometry.Point([-122.27, 37.87]).buffer(1000), scale=1, bestEffort=True, ) ) # EEException: User memory limit exceeded. print(memory_hog.getInfo())
Этот очень плохой код демонстрирует одну из причин, по которой не следует использовать массивы, если в этом нет особой необходимости (см. также раздел «Избегайте ненужного преобразования типов»). Когда эта коллекция преобразуется в гигантский массив, весь массив необходимо загрузить в память сразу. Поскольку это длинный временной ряд изображений, массив большой и не помещается в памяти.
Одним из возможных решений является установка более высокого значения для параметра tileScale
. Более высокие значения tileScale приводят к уменьшению плиток в tileScale^2
. Например, следующее позволяет успешно выполнить вычисление:
Редактор кода (JavaScript)
var bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7']; var smallerHog = ee.ImageCollection('LANDSAT/LT05/C02/T1').select(bands) .toArray() .arrayReduce(ee.Reducer.mean(), [0]) .arrayProject([1]) .arrayFlatten([bands]) .reduceRegion({ reducer: 'mean', geometry: ee.Geometry.Point([-122.27, 37.87]).buffer(1000), scale: 1, bestEffort: true, tileScale: 16 }); print(smallerHog);
import ee import geemap.core as geemap
Колаб (Питон)
bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'] smaller_hog = ( ee.ImageCollection('LANDSAT/LT05/C02/T1') .select(bands) .toArray() .arrayReduce(ee.Reducer.mean(), [0]) .arrayProject([1]) .arrayFlatten([bands]) .reduceRegion( reducer=ee.Reducer.mean(), geometry=ee.Geometry.Point([-122.27, 37.87]).buffer(1000), scale=1, bestEffort=True, tileScale=16, ) ) print(smaller_hog.getInfo())
Однако гораздо более предпочтительное решение — не использовать массивы без необходимости, поэтому вам вообще не нужно возиться с tileScale
:
Хорошо — избегайте массивов!
Редактор кода (JavaScript)
var bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7']; var okMemory = ee.ImageCollection('LANDSAT/LT05/C02/T1').select(bands) .mean() .reduceRegion({ reducer: 'mean', geometry: ee.Geometry.Point([-122.27, 37.87]).buffer(1000), scale: 1, bestEffort: true, }); print(okMemory);
import ee import geemap.core as geemap
Колаб (Питон)
bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'] ok_memory = ( ee.ImageCollection('LANDSAT/LT05/C02/T1') .select(bands) .mean() .reduceRegion( reducer=ee.Reducer.mean(), geometry=ee.Geometry.Point([-122.27, 37.87]).buffer(1000), scale=1, bestEffort=True, ) ) print(ok_memory.getInfo())
Если нет необходимости устранить ошибку памяти, не следует устанавливать tileScale
, поскольку меньшие плитки также приводят к увеличению накладных расходов на распараллеливание.
Внутренние ошибки
Вы можете столкнуться с ошибкой, которая выглядит следующим образом:
Если вы получили эту ошибку, нажмите ссылку «Сообщить об ошибке», которая появляется в консоли редактора кода JavaScript. Вы также можете отправить отзыв с помощью кнопки «Справка» . Эта ошибка может быть результатом логических ошибок в вашем скрипте, которые становятся очевидными только во время выполнения, или проблемы с внутренней работой Earth Engine. В любом случае ошибка неинформативна, и о ней следует сообщить, чтобы ее можно было исправить.
Внутренние ошибки включают идентификатор request
, например:
Эти строки действуют как уникальные идентификаторы, помогая команде Earth Engine выявлять конкретные проблемы. Включите эту строку в отчеты об ошибках.
Методы отладки
Вы закодировали свой анализ, запустили его и получили ошибку. И что теперь? В этом разделе описаны общие методы отладки, позволяющие локализовать проблему и устранить ее.
Проверка переменных и слоев карты
Предположим, у вас очень сложный анализ, который выдает ошибку. Если неясно, откуда возникла ошибка, хорошей первоначальной стратегией будет распечатать или визуализировать промежуточные объекты и проверить их, чтобы убедиться, что структура объекта соответствует логике вашего скрипта. В частности, вы можете проверять значения пикселей слоев, добавленных на карту, с помощью редактора кода или инструментов инспектора Geemap. Если вы что-то распечатываете, обязательно разверните его свойства с помощью застежек-молний (▶). Некоторые вещи, которые следует проверить, включают в себя:
- Названия групп. Соответствуют ли названия полос изображений вашему коду?
- Пиксельные значения. Имеют ли ваши данные правильный диапазон? Правильно ли оно замаскировано?
- Нулевой. Есть ли что-то нулевое, чего не должно быть?
- Размеры. Является ли размер нулевым, хотя его быть не должно?
aside()
Поместить каждый промежуточный этап анализа в переменную, чтобы ее можно было распечатать и проверить, может оказаться затруднительно. Чтобы напечатать промежуточные значения из длинной цепочки вызовов функций, вы можете использовать методside aside()
. Например:
Редактор кода (JavaScript)
var image = ee.Image(ee.ImageCollection('COPERNICUS/S2') .filterBounds(ee.Geometry.Point([-12.29, 168.83])) .aside(print) .filterDate('2011-01-01', '2016-12-31') .first());
import ee import geemap.core as geemap
Колаб (Питон)
image = ee.Image( ee.ImageCollection('COPERNICUS/S2_HARMONIZED') .filterBounds(ee.Geometry.Point([-12.29, 168.83])) .aside(display) .filterDate('2011-01-01', '2016-12-31') .first() )
Просто помните, aside(print)
(Редактор кода JavaScript) и aside(display)
(Python geemap) вызывают функции на стороне клиента, и в сопоставленных функциях это все равно приведет к сбою . Вы также можете использовать его с пользовательскими функциями. Например:
Редактор кода (JavaScript)
var composite = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') .filterBounds(ee.Geometry.Point([106.91, 47.91])) .map(function(image) { return image.addBands(image.normalizedDifference(['B5', 'B4'])); }) .aside(Map.addLayer, {bands: ['B4', 'B3', 'B2'], max: 0.3}, 'collection') .qualityMosaic('nd'); Map.setCenter(106.91, 47.91, 11); Map.addLayer(composite, {bands: ['B4', 'B3', 'B2'], max: 0.3}, 'composite');
import ee import geemap.core as geemap
Колаб (Питон)
m = geemap.Map() m.set_center(106.91, 47.91, 11) composite = ( ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') .filterBounds(ee.Geometry.Point([106.91, 47.91])) .map(lambda image: image.addBands(image.normalizedDifference(['B5', 'B4']))) .aside(m.add_layer, {'bands': ['B4', 'B3', 'B2'], 'max': 0.3}, 'collection') .qualityMosaic('nd') ) m.add_layer(composite, {'bands': ['B4', 'B3', 'B2'], 'max': 0.3}, 'composite') m
Запуск функции first()
Печать и визуализация полезны для отладки, если они доступны, но когда вы отлаживаете функцию, сопоставленную с коллекцией, вы не можете напечатать функцию, как описано в разделе «Сопоставленные функции» . В этом случае полезно изолировать проблемные элементы в коллекции и протестировать отображаемую функцию на отдельном элементе. Когда вы тестируете функцию без ее сопоставления, вы можете использовать операторы печати, чтобы понять проблему. Рассмотрим следующий пример.
Ошибка — этот код не работает!
Редактор кода (JavaScript)
var image = ee.Image( 'COPERNICUS/S2_HARMONIZED/20150821T111616_20160314T094808_T30UWU'); var someFeatures = ee.FeatureCollection([ ee.Feature(ee.Geometry.Point([-2.02, 48.43])), ee.Feature(ee.Geometry.Point([-2.80, 48.37])), ee.Feature(ee.Geometry.Point([-1.22, 48.29])), ee.Feature(ee.Geometry.Point([-1.73, 48.65])), ]); var problem = someFeatures.map(function(feature) { var dictionary = image.reduceRegion({ reducer: 'first', geometry: feature.geometry(), scale: 10, }); return feature.set({ result: ee.Number(dictionary.get('B5')) .divide(dictionary.get('B4')) }); }); // Error in map(ID=2): // Number.divide: Parameter 'left' is required. print(problem);
import ee import geemap.core as geemap
Колаб (Питон)
image = ee.Image( 'COPERNICUS/S2_HARMONIZED/20150821T111616_20160314T094808_T30UWU' ) some_features = ee.FeatureCollection([ ee.Feature(ee.Geometry.Point([-2.02, 48.43])), ee.Feature(ee.Geometry.Point([-2.80, 48.37])), ee.Feature(ee.Geometry.Point([-1.22, 48.29])), ee.Feature(ee.Geometry.Point([-1.73, 48.65])), ]) # Define a function to be mapped over the collection. def function_to_map(feature): dictionary = image.reduceRegion( reducer=ee.Reducer.first(), geometry=feature.geometry(), scale=10 ) return feature.set( {'result': ee.Number(dictionary.get('B5')).divide(dictionary.get('B4'))} ) problem = some_features.map(function_to_map) # EEException: Error in map(ID=2): # Number.divide: Parameter 'left' is required. print(problem.getInfo())
Чтобы отладить это, рекомендуется изучить ошибку. К счастью, эта полезная ошибка сообщает вам о проблеме с функцией с ID=2
. Для дальнейшего изучения полезно немного реорганизовать код. В частности, вы не можете использовать операторы печати в функции, если она сопоставлена с коллекцией, как описано в этом разделе. Цель отладки — изолировать проблемную функцию и запустить функцию с некоторыми операторами печати. С тем же изображением и функциями, которые использовались ранее:
Редактор кода (JavaScript)
// Define a function to be mapped over the collection. var functionToMap = function(feature) { var dictionary = image.reduceRegion({ reducer: 'first', geometry: feature.geometry(), scale: 10, }); // Debug: print(dictionary); return feature.set({ result: ee.Number(dictionary.get('B5')) .divide(dictionary.get('B4')) }); }; // Isolate the feature that's creating problems. var badFeature = ee.Feature(someFeatures .filter(ee.Filter.eq('system:index', '2')) .first()); // Test the function with print statements added. functionToMap(badFeature); // Inspect the bad feature in relation to the image. Map.centerObject(badFeature, 11); Map.addLayer(badFeature, {}, 'bad feature'); Map.addLayer(image, {bands: ['B4', 'B3', 'B2'], max: 3000}, 'image');
import ee import geemap.core as geemap
Колаб (Питон)
# Define a function to be mapped over the collection. def function_to_map(feature): dictionary = image.reduceRegion( reducer=ee.Reducer.first(), geometry=feature.geometry(), scale=10 ) # Debug: display(dictionary) return feature.set( {'result': ee.Number(dictionary.get('B5')).divide(dictionary.get('B4'))} ) # Isolate the feature that's creating problems. bad_feature = ee.Feature( some_features.filter(ee.Filter.eq('system:index', '2')).first() ) # Test the function with print statements added. function_to_map(bad_feature) # Inspect the bad feature in relation to the image. m = geemap.Map() m.center_object(bad_feature, 11) m.add_layer(bad_feature, {}, 'bad feature') m.add_layer(image, {'bands': ['B4', 'B3', 'B2'], 'max': 3000}, 'image') m
Теперь, поскольку функция запускается только для одного объекта, вы можете поместить внутрь вызов print («display» для Python Geemap). Осмотрите напечатанный объект и обнаружите (аха!), что объект, возвращаемый функцией reduceRegion()
имеет нули для каждой полосы. Это объясняет, почему деление не удается: потому что вы не можете разделить ноль на ноль. Почему оно вообще равно нулю? Для исследования добавьте входное изображение и плохой объект на карту и сосредоточьтесь на плохом объекте. При этом вы обнаружите, что проблема связана с тем, что точка находится за пределами изображения. На основе этого открытия отлаживаемый код выглядит следующим образом:
Редактор кода (JavaScript)
var functionToMap = function(feature) { var dictionary = image.reduceRegion({ reducer: 'first', geometry: feature.geometry(), scale: 10, }); return feature.set({ result: ee.Number(dictionary.get('B5')) .divide(dictionary.get('B4')) }); }; var noProblem = someFeatures .filterBounds(image.geometry()) .map(functionToMap); print(noProblem);
import ee import geemap.core as geemap
Колаб (Питон)
def function_to_map(feature): dictionary = image.reduceRegion( reducer=ee.Reducer.first(), geometry=feature.geometry(), scale=10 ) return feature.set( {'result': ee.Number(dictionary.get('B5')).divide(dictionary.get('B4'))} ) no_problem = some_features.filterBounds(image.geometry()).map(function_to_map) display(no_problem)
Профайлер
Профилировщик предоставляет информацию о времени EECU и использовании памяти (для каждого алгоритма и актива), полученную в результате вычислений, выполняемых, пока он включен. Найдите записи в верхней части профилировщика для получения информации о наиболее ресурсоемких операциях. Для долго выполняемых или неэффективных сценариев записи в верхней части профилировщика дают подсказки о том, на чем сосредоточить усилия по оптимизации сценария. Важное замечание: сам профилировщик влияет на производительность скрипта, поэтому запускать его следует только при необходимости.