Los algoritmos que creas en Earth Engine se ejecutan en la nube de Google, distribuidos en muchas computadoras. La depuración puede ser un desafío, ya que los errores pueden ocurrir en el código del cliente o en la ejecución del servidor de las instrucciones codificadas, y pueden deberse a problemas de escalamiento, así como a errores sintácticos o lógicos. Los bits del programa que se ejecutan en algún lugar de la nube no están disponibles para su inspección, a menos que los solicites. En este documento, se presentan estrategias, herramientas y soluciones de depuración para ayudarte a resolver errores comunes y depurar secuencias de comandos de Earth Engine.
Errores de sintaxis
Los errores de sintaxis ocurren cuando tu código incumple las reglas del lenguaje de programación (JavaScript o Python en Earth Engine). Estos errores impiden que se ejecute el código y, por lo general, se detectan antes de la ejecución. Si encuentras un error de sintaxis, revisa cuidadosamente la línea destacada o el mensaje de error, y consulta recursos como la Referencia del lenguaje Python o la Guía de estilo de JavaScript de Google. Un linteador de código también puede ayudar a identificar y corregir estos problemas.
Errores del cliente
A pesar de que el código es sintácticamente correcto, es posible que haya errores asociados con la coherencia o la lógica de la secuencia de comandos. En los siguientes ejemplos, se muestran errores por usar una variable y un método que no existen.
Error: Este código no funciona.
Editor de código (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
Colab (Python)
# 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()
El primer error te informa que la variable bandNames
no está definida en el alcance en el que se hace referencia a ella. Como solución, configura la variable o proporciona un argumento de lista para el parámetro bands
. El segundo error demuestra lo que sucede cuando se llama a la función selfAnalyze()
inexistente. Como
ese no es un método real en las imágenes, el error te indica que no es una función. En ambos casos, el error describe el problema.
Conversión de tipo de objeto desconocido
El error "...is not a function
" puede deberse a que Earth Engine no conoce el tipo de una variable. Las manifestaciones comunes de este problema se deben a lo siguiente:
- Hacer algo con un objeto que muestra
first()
(el tipo de elementos de una colección es desconocido) - Hacer algo con un objeto que muestra
get()
(se desconoce el tipo de elemento almacenado en una propiedad) - Hacer algo con un argumento de función (en la función) cuando se desconoce el tipo del argumento
A modo de ejemplo, este es el caso de lo primero:
Error: Este código no funciona.
Editor de código (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
Colab (Python)
collection = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') # AttributeError: 'Element' object has no attribute 'area'. area = collection.first().area()
La solución en todos los casos es transmitir el objeto de tipo desconocido con el constructor del tipo conocido. Siguiendo con el ejemplo anterior, la solución es transmitir a ee.Feature
:
Solución: Usa un transmisor.
Editor de código (JavaScript)
var area = ee.Feature(collection.first()).area();
import ee import geemap.core as geemap
Colab (Python)
area = ee.Feature(collection.first()).area()
(Cabe destacar que puedes llamar de forma segura a cualquier método en Element
aquí, ya que eso es lo que Earth Engine cree que es).
Evita mezclar funciones de cliente y servidor
El siguiente ejemplo es menos obvio:
Error: Este código no hace lo que quieres.
Editor de código (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
Colab (Python)
# 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
Suponiendo que el autor de este código tenía la intención de agregar 2
a cada píxel de la imagen, esta no es la forma correcta de hacerlo. Específicamente, este código combina de forma incorrecta un objeto del servidor (image
) con un operador del cliente (+
). Los resultados pueden ser sorprendentes. En el primer caso, la impresión de nonsense
en el editor de código de JavaScript realizará la operación solicitada (+
) convirtiendo image
y 2
en cadenas y, luego, concatenando. La cadena resultante no es deseada (en Python, se genera una TypeError).
En el segundo caso, cuando se agrega nonsense
al mapa, se muestra el error críptico g.eeObject.name is not a function
en el editor de código de JavaScript porque el objeto que se agrega al mapa, nonsense
, es una cadena, no un objeto EE (en Python, se genera un TypeError). Para evitar resultados no deseados y errores poco informativos, no mezcles objetos y funciones del servidor con objetos, funciones o primitivas del cliente. La solución en este ejemplo es usar una función de servidor.
Solución: Usa una función del servidor.
Editor de código (JavaScript)
Map.addLayer(image.add(2));
import ee import geemap.core as geemap
Colab (Python)
m = geemap.Map() m.add_layer(image.add(2)) m
Consulta la página Cliente frente a servidor para obtener más detalles.
Bloqueo del navegador del editor de código JavaScript
El navegador puede bloquearse o congelarse cuando JavaScript se ejecuta en el cliente demasiado tiempo o cuando se espera algo de Earth Engine. Dos fuentes comunes de este error son los bucles for o getInfo()
en el código del editor de código de JavaScript, con el peor de los casos de getInfo()
dentro de un bucle for. Los bucles for pueden hacer que el navegador se bloquee porque el código se ejecuta en tu máquina. Por otro lado,
getInfo()
solicita de forma síncrona el resultado de un procesamiento de Earth Engine,
bloqueando hasta que se recibe el resultado. Si el procesamiento tarda mucho, el bloqueo podría hacer que el navegador se bloquee. Evita los bucles for y getInfo()
mientras trabajas en el editor de código. Consulta la página Cliente frente a servidor para obtener más detalles.
Errores del servidor
A pesar de la coherencia lógica en el código del cliente, puede haber errores que solo se hacen evidentes durante el tiempo de ejecución en el servidor. En el siguiente ejemplo, se muestra lo que sucede cuando se intenta obtener una banda que no existe.
Error: Este código no funciona.
Editor de código (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
Colab (Python)
# 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())
En este ejemplo, el error te informa que no hay ninguna banda llamada nonBand
. La solución posiblemente obvia es especificar un nombre de banda que exista. Para descubrir los nombres de las bandas, imprime la imagen y
mírala en la consola, o bien imprime la lista de nombres de bandas que muestra
image.bandNames()
.
Inmutabilidad
Los objetos del servidor que creas en Earth Engine son
immutable. (cualquier ee.Object
es un Object
del servidor). Eso significa que, si quieres realizar un cambio en el objeto, debes guardar el estado modificado en una variable nueva. Por ejemplo, esto no funcionará para establecer una propiedad en la imagen de Sentinel-2:
Error: Este código no hace lo que quieres.
Editor de código (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
Colab (Python)
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
En este ejemplo, s2image.set()
muestra una copia de la imagen con la propiedad nueva, pero la imagen almacenada en la variable s2image
no se modifica. Debes guardar la imagen que muestra s2image.set()
en una variable nueva. Por ejemplo:
Solución: Captura el resultado en una variable.
Editor de código (JavaScript)
s2image = s2image.set('myProperty', 'OK'); print(s2image.get('myProperty')); // OK
import ee import geemap.core as geemap
Colab (Python)
s2image = s2image.set('my_property', 'OK') display(s2image.get('my_property')) # OK
Funciones asignadas
Otro contexto en el que no se mezclan las funciones del cliente y del servidor es en las funciones asignadas. Específicamente, las operaciones especificadas por la función asignada se ejecutan en la nube,
por lo que las funciones del cliente, como getInfo
y Export
(así como print
y el método en Map
y Chart
en
el editor de código de JavaScript), no funcionarán en las funciones asignadas. Por ejemplo:
Error: Este código no funciona.
Editor de código (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
Colab (Python)
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()))
Este error algo críptico se debe al proceso que usa Earth Engine para convertir este código en un conjunto de instrucciones que se pueden ejecutar en los servidores de Google. Las funciones del cliente y las estructuras de control no se pueden usar para operar en la imagen del argumento que se pasa a la función asignada. Para evitar este error, evita el uso de funciones del cliente en funciones asignadas. Consulta la página Cliente frente a servidor para obtener más información sobre la distinción entre las funciones del cliente y del servidor.
Las funciones asignadas tienen requisitos adicionales. Por ejemplo, las funciones asignadas deben mostrar algo:
Error: Este código no funciona.
Editor de código (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
Colab (Python)
collection = ee.ImageCollection('MODIS/006/MOD44B') # Error: User-defined methods must return a value. bad_map_1 = collection.map(lambda image: None)
La solución más obvia es devolver algo. Pero no puede mostrar cualquier tipo de elemento. Específicamente, las funciones asignadas a un ImageCollection
o FeatureCollection
deben mostrar un Image
o Feature
. Por ejemplo, no puedes mostrar una fecha de una función asignada a un ImageCollection
:
Error: Este código no funciona.
Editor de código (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
Colab (Python)
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())
Para evitar esto, muestra la imagen de entrada con un nuevo conjunto de propiedades. Luego, si necesitas una lista
de las fechas de las imágenes de la colección, puedes usar aggregate_array()
:
Solución: Establece una propiedad.
Editor de código (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
Colab (Python)
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())
Errores de procedimiento
Se aplicó el patrón a una imagen sin bandas.
El error "Pattern 'my_band' was applied to an Image with no bands"
significa que hay una llamada ee.Image.select()
para una imagen con una lista de bandas vacía. Puedes hacer lo siguiente para solucionar este problema:
- Si la imagen se produce a partir de un ImageCollection con un reductor o con las llamadas
first()
otoBands()
, asegúrate de que la colección de origen no esté vacía. - Si la imagen se produce a partir de un diccionario con
ee.Dictionary().toImage()
, asegúrate de que el diccionario no esté vacío. - Si la imagen es independiente, asegúrate de que tenga datos (y no solo sea
ee.Image(0)
).
Errores de escalamiento
Aunque una secuencia de comandos puede ser correcta sintácticamente, sin errores lógicos y representar un conjunto de instrucciones válido para el servidor, cuando se paraleliza y ejecuta el procesamiento, los objetos resultantes pueden ser demasiado grandes, demasiado numerosos o tardar demasiado en procesarse. En este caso, recibirás un error que indica que no se puede escalar el algoritmo. Por lo general, estos errores son los más difíciles de diagnosticar y resolver. Estos son algunos ejemplos de este tipo de error:
- Se agotó el tiempo de espera del procesamiento
- Demasiadas agregaciones simultáneas
- Se superó el límite de memoria del usuario
- Se produjo un error interno
Mejorar la escalabilidad de tu código te permitirá obtener resultados más rápido y también mejorar la disponibilidad de recursos de procesamiento para todos los usuarios. Cada tipo de error se analiza en las siguientes secciones, después de una breve digresión sobre reduceRegion()
, una función de uso general que es conocida por poder causar todo tipo de error de escalamiento.
reduceRegion()
Aunque reduceRegion()
consume con avidez suficientes píxeles para activar una variedad emocionante de errores, también hay parámetros destinados a controlar el procesamiento para que puedas superar los errores. Por ejemplo, considera la siguiente
reducción no recomendable:
Error: Este código no funciona.
Editor de código (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
Colab (Python)
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())
Este ejemplo es solo para demostración. El propósito de este error es preguntarte si realmente quieres reducir 80300348117 (80 mil millones) de píxeles. De lo contrario, aumenta scale
(tamaño de píxeles en metros) según corresponda o establece bestEffort
como verdadero para volver a calcular una escala más grande automáticamente. Consulta la página reduceRegion()
para obtener más detalles sobre estos parámetros.
Se agotó el tiempo de espera del procesamiento
Supongamos que necesitas todos esos píxeles en tu cálculo. Si es así, puedes aumentar el parámetro maxPixels
para permitir que el procesamiento se realice correctamente. Sin embargo, Earth Engine tardará un tiempo en terminar el procesamiento. Como resultado, es posible que se muestre un error de “tiempo de espera de procesamiento”:
Mala: No lo hagas.
Editor de código (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
Colab (Python)
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())
Esto significa que Earth Engine esperó alrededor de cinco minutos antes de detener el cálculo. La exportación permite que Earth Engine realice el procesamiento en un entorno con tiempos de ejecución más largos (pero no con más memoria). Como el valor que se muestra de reduceRegion()
es un diccionario, puedes usarlo para establecer las propiedades de un componente con geometría nula:
Buena: Usa Export
.
Editor de código (JavaScript)
Export.table.toDrive({ collection: ee.FeatureCollection([ ee.Feature(null, ridiculousComputation) ]), description: 'ridiculousComputation', fileFormat: 'CSV' });
import ee import geemap.core as geemap
Colab (Python)
task = ee.batch.Export.table.toDrive( collection=ee.FeatureCollection([ee.Feature(None, ridiculous_computation)]), description='ridiculous_computation', fileFormat='CSV', ) # task.start()
Demasiadas agregaciones simultáneas
La parte "aggregations" de este error hace referencia a las operaciones que se distribuyen en varias máquinas (como las reducciones que abarcan más de una tarjeta). Earth Engine tiene límites para evitar que se ejecuten demasiados de estos procesos de agregación de forma simultánea. En este ejemplo, el error "Demasiadas agregaciones simultáneas" se activa debido a una reducción dentro de un mapa:
Mala: No lo hagas.
Editor de código (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
Colab (Python)
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())
Suponiendo que el propósito de este código es obtener estadísticas de imagen para cada imagen, una posible solución es Export
el resultado. Por ejemplo, con el hecho de que un ImageCollection
también es un FeatureCollection
, los metadatos asociados con las imágenes se pueden exportar como una tabla:
Buena: Usa Export
.
Editor de código (JavaScript)
Export.table.toDrive({ collection: terribleAggregations, description: 'terribleAggregations', fileFormat: 'CSV' });
import ee import geemap.core as geemap
Colab (Python)
task = ee.batch.Export.table.toDrive( collection=terrible_aggregations, description='terrible_aggregations', fileFormat='CSV', ) # task.start()
Se superó el límite de memoria del usuario
Una forma de paralelizar tus algoritmos en Earth Engine es dividir las entradas en mosaicos, ejecutar el mismo procesamiento por separado en cada mosaico y, luego, combinar los resultados. Como consecuencia, todas las entradas necesarias para calcular una tarjeta de salida deben caber en la memoria. Por ejemplo, cuando la entrada es una imagen con muchas bandas, podría ocupar mucha memoria si se usan todas las bandas en el procesamiento. A modo de demostración, este ejemplo usa demasiada memoria, ya que fuerza (de forma innecesaria) una colección de imágenes completa en una tarjeta:
Mala: No lo hagas.
Editor de código (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
Colab (Python)
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())
Este código muy malo demuestra un motivo para no usar arrays, a menos que realmente lo necesites (consulta también la sección "Evita convertir tipos innecesariamente"). Cuando esa colección se convierte en un array gigantesco, el array se debe cargar en la memoria de una sola vez. Debido a que es una serie temporal larga de imágenes, el array es grande y no cabe en la memoria.
Una solución posible es establecer el parámetro tileScale
en un valor más alto. Los valores más altos de tileScale generan mosaicos más pequeños por un factor de tileScale^2
. Por ejemplo, lo siguiente permite que el cálculo se realice correctamente:
Editor de código (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
Colab (Python)
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())
Sin embargo, la solución más preferida es no usar arrays innecesariamente, por lo que no necesitas manipular tileScale
:
Bien: Evita los Arrays.
Editor de código (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
Colab (Python)
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())
A menos que sea necesario para resolver un error de memoria, no debes configurar tileScale
, ya que las tarjetas más pequeñas también generan una sobrecarga de paralelización mayor.
Errores internos
Es posible que se vea un error como el siguiente:
Si recibes este error, haz clic en el vínculo "Informar error" que aparece en la consola del editor de código de JavaScript. También puedes enviar comentarios desde el botón Ayuda. Este error puede deberse a errores lógicos en la secuencia de comandos que solo se hacen evidentes durante el tiempo de ejecución o a un problema con el funcionamiento interno de Earth Engine. En cualquier caso, el error no es informativo y se debe informar para que se pueda corregir.
Los errores internos incluyen un ID request
, como el siguiente:
Estas cadenas actúan como identificadores únicos para ayudar al equipo de Earth Engine a identificar problemas específicos. Incluye esta cadena en los informes de errores.
Métodos de depuración
Programaste tu análisis, lo ejecutaste y recibiste un error. ¿Qué sigue? En esta sección, se describen técnicas generales de depuración para aislar el problema y solucionarlo.
Inspecciona las variables y las capas del mapa
Supongamos que tienes un análisis muy complejo que produce un error. Si no es obvio de dónde proviene el error, una buena estrategia inicial es imprimir o visualizar objetos intermedios y, luego, inspeccionarlos para garantizar que la estructura del objeto sea coherente con la lógica de la secuencia de comandos. Específicamente, puedes inspeccionar los valores de píxeles de las capas agregadas al mapa con el Editor de código o las herramientas del Inspector de geemap. Si imprimes algo, asegúrate de expandir sus propiedades con los menús desplegables (▶). Estos son algunos aspectos que debes verificar:
- Nombres de bandas ¿Los nombres de las bandas de imágenes coinciden con tu código?
- Valores de píxeles ¿Tus datos tienen el rango correcto? ¿Está enmascarado de forma adecuada?
- Nulo. ¿Hay algún valor nulo que no debería serlo?
- Tamaños. ¿El tamaño es cero cuando no debería serlo?
aside()
Puede ser engorroso colocar cada paso intermedio de un análisis en una variable para que se pueda imprimir e inspeccionar. Para imprimir valores intermedios de una larga cadena de llamadas a función, puedes usar el método aside()
. Por ejemplo:
Editor de código (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
Colab (Python)
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() )
Solo recuerda que aside(print)
(editor de código de JavaScript) y aside(display)
(geemap de Python) llaman a funciones del cliente y, de todos modos, fallarán en las funciones asignadas. También puedes usar aside con funciones definidas por el usuario. Por ejemplo:
Editor de código (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
Colab (Python)
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
Ejecuta una función en first()
La impresión y la visualización son útiles para depurar cuando están disponibles, pero cuando depuras una función asignada a una colección, no puedes imprimir en la función, como se describe en la sección de funciones asignadas. En este caso, es útil aislar los elementos problemáticos de la colección y probar la función asignada en un elemento individual. Cuando pruebes la función sin asignarla, puedes usar instrucciones de impresión para comprender el problema. Considera el siguiente ejemplo:
Error: Este código no funciona.
Editor de código (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
Colab (Python)
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())
Para depurar esto, es instructivo examinar el error. Afortunadamente, este error útil
te informa que hay un problema con la función de ID=2
. Para investigar más, es útil refactorizar un poco el código. Específicamente, no puedes tener instrucciones de impresión en la función cuando se asigna a una colección, como se describe en esta sección. El objetivo de la depuración es aislar la función problemática y ejecutar la función con algunas sentencias de impresión. Con la misma imagen y las mismas funciones que se usaron anteriormente:
Editor de código (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
Colab (Python)
# 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
Ahora, como la función se ejecuta solo en un componente, puedes colocar una llamada de impresión ("display" para geemap de Python) dentro. Inspecciona el objeto impreso para descubrir (¡ajá!) que el objeto que muestra reduceRegion()
tiene valores nulos para cada banda. Eso explica por qué falla la
división: porque no puedes dividir nulo por nulo. ¿Por qué es nulo en primer lugar?
Para investigar, agrega la imagen de entrada y el componente incorrecto al mapa, y céntrate en este. Al hacerlo, descubres que el problema se debe a que el punto está fuera de los límites de la imagen. En función de este descubrimiento, el código depurado es el siguiente:
Editor de código (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
Colab (Python)
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)
Profiler
El generador de perfiles proporciona información sobre el tiempo de EECU y el uso de memoria (por algoritmo y recurso) que resulta del procesamiento que se realiza mientras está habilitado. Busca las entradas en la parte superior del generador de perfiles para obtener información sobre las operaciones que consumen más recursos. En el caso de las secuencias de comandos de larga duración o ineficientes, las entradas en la parte superior del generador de perfiles proporcionan pistas sobre dónde enfocar los esfuerzos para optimizar la secuencia de comandos. Nota importante: El generador de perfiles influye en el rendimiento de la secuencia de comandos, por lo que solo debes ejecutarlo cuando sea necesario.