Gli algoritmi che crei in Earth Engine vengono eseguiti nel cloud di Google, distribuiti su molti computer. Il debug può essere complicato perché gli errori possono verificarsi nel codice lato client o nell'esecuzione lato server delle istruzioni codificate e possono essere causati da problemi di scalabilità, nonché da errori sintattici o logici. I bit del programma in esecuzione da qualche parte nel cloud non sono disponibili per l'ispezione, a meno che tu non li chieda. Questo documento presenta strategie, strumenti e soluzioni di debug per aiutarti a risolvere gli errori comuni e a eseguire il debug degli script di Earth Engine.
Errori di sintassi
Gli errori di sintassi si verificano quando il codice viola le regole del linguaggio di programmazione (JavaScript o Python in Earth Engine). Questi errori impediscono l'esecuzione del codice e di solito vengono rilevati prima dell'esecuzione. Se riscontri un errore di sintassi, esamina attentamente la riga evidenziata o il messaggio di errore e consulta risorse come la Documentazione del linguaggio Python o la Guida allo stile di Google JavaScript. Anche un lint per il codice può aiutarti a identificare e risolvere questi problemi.
Errori lato client
Nonostante il codice sia sintatticamente corretto, potrebbero esserci errori associati alla coerenza o alla logica dello script. Gli esempi seguenti mostrano gli errori derivanti dall'utilizzo di una variabile e di un metodo inesistenti.
Errore: questo codice non funziona.
Editor di codice (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()
Il primo errore ti informa che la variabile bandNames
non è definita
nell'ambito a cui fa riferimento. Come soluzione, imposta la variabile o fornisci un
parametro di elenco per il parametro bands
. Il secondo errore mostra cosa accade quando viene richiamata la funzione inesistente selfAnalyze()
. Poiché
non si tratta di un metodo reale per le immagini, l'errore indica che non è una funzione. In entrambi i casi, l'errore è descrittivo del problema.
Conversione di tipo di oggetto sconosciuta
L'errore "...is not a function
" potrebbe derivare dal fatto che Earth Engine non conosce il tipo di una variabile. Le manifestazioni comuni di questo problema derivano da:
- Eseguire un'operazione su un oggetto restituito da
first()
(il tipo di elementi di una raccolta è sconosciuto). - Eseguire un'operazione su un oggetto restituito da
get()
(il tipo di elemento memorizzato in una proprietà è sconosciuto). - Eseguire un'operazione su un argomento di funzione (nella funzione) quando il tipo dell'argomento è sconosciuto.
Ecco un esempio del primo:
Errore: questo codice non funziona.
Editor di codice (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()
In tutti i casi, la soluzione è eseguire il casting dell'oggetto di tipo sconosciuto con il costruttore
del tipo noto. Continuando con l'esempio precedente, la soluzione è eseguire il trasferimento a
ee.Feature
:
Soluzione: usa una trasmissione.
Editor di codice (JavaScript)
var area = ee.Feature(collection.first()).area();
import ee import geemap.core as geemap
Colab (Python)
area = ee.Feature(collection.first()).area()
(Vale la pena notare che puoi chiamare in sicurezza qualsiasi metodo su Element
qui
perché è quello che pensa Earth Engine).
Evita di mescolare funzioni client e server
L'esempio seguente è meno evidente:
Errore: questo codice non fa ciò che vuoi
Editor di codice (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
Supponendo che l'autore di questo codice volesse aggiungere 2
a ogni pixel dell'immagine, questo non è il modo giusto per farlo. Nello specifico, questo codice mescola erroneamente un
oggetto lato server (image
) con un operatore lato client
(+
). I risultati potrebbero essere sorprendenti. Nel primo caso, l'output di
nonsense
nell'editor di codice JavaScript eseguirà l'operazione richiesta
(+
) convertendo sia image
sia 2
in stringhe,
quindi concatenandole. La stringa risultante non è prevista (in Python viene generato un TypeError).
Nel secondo caso, aggiungendo nonsense
alla mappa, viene visualizzato l'errore enigmatico
g.eeObject.name is not a function
nell'editor di codice JavaScript
perché l'oggetto aggiunto alla mappa, nonsense
, è una stringa, non un
oggetto EE (in Python viene generato un TypeError). Per evitare risultati potenzialmente indesiderati e
errori poco informativi, non mescolare oggetti e funzioni del server con oggetti, primitive o funzioni
del client. La soluzione in questo esempio è utilizzare una funzione del server.
Soluzione: utilizza una funzione del server.
Editor di codice (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
Per ulteriori dettagli, consulta la pagina Client e server.
Blocco del browser dell'editor di codice JavaScript
Il blocco o il blocco del browser può verificarsi quando l'esecuzione di JavaScript nel client richiede troppo tempo o
quando si attende qualcosa da Earth Engine. Due cause comuni di questo errore sono
i cicli for e/o getInfo()
nel codice di Editor di codice JavaScript, con il
peggiore scenario di getInfo()
all'interno di un ciclo for. I cicli for possono causare il blocco del browser perché il codice viene eseguito sulla tua macchina. D'altra parte,
getInfo()
richiede in modo sincrono il risultato di un calcolo da Earth Engine,
bloccandosi fino alla ricezione del risultato. Se il calcolo richiede molto tempo, il blocco potrebbe causare il blocco del browser. Evita sia i cicli for che getInfo()
mentre lavori nell'editor di codice. Per ulteriori dettagli, consulta la pagina Client e server.
Errori lato server
Nonostante la coerenza logica nel codice client, potrebbero esserci bug che diventano evidenti solo in fase di esecuzione sul server. L'esempio seguente mostra cosa accade quando si tenta di ottenere una banda inesistente.
Errore: questo codice non funziona.
Editor di codice (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())
In questo esempio, l'errore ti informa che non esiste una banda denominata
nonBand
. La soluzione forse più ovvia è specificare il nome di un gruppo che
esiste. Puoi scoprire i nomi delle bande stampando l'immagine e esaminandola nella console o stampando l'elenco dei nomi delle bande restituiti da image.bandNames()
.
Immutabilità
Gli oggetti lato server creati in Earth Engine sono
immutable. (Qualsiasi
ee.Object
è un Object
lato server). Ciò significa che se
vuoi apportare una modifica all'oggetto, devi salvare lo stato modificato in una nuova
variabile. Ad esempio, non funzionerà per impostare una proprietà sull'immagine Sentinel-2:
Errore: questo codice non fa quello che vuoi.
Editor di codice (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
In questo esempio, s2image.set()
restituisce una copia dell'immagine con la nuova proprietà, ma l'immagine memorizzata nella variabile s2image
rimane invariata. Devi
salvare l'immagine restituita da s2image.set()
in una nuova variabile. Ad esempio:
Soluzione: acquisisci il risultato in una variabile.
Editor di codice (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
Funzioni mappate
Un altro contesto in cui le funzioni client e server non si mescolano è nelle funzioni mappate. Nello specifico, le operazioni specificate dalla funzione mappata vengono eseguite nel cloud,
quindi le funzioni client come getInfo
e Export
(nonché print
e il metodo su Map
e Chart
nell'Editor di codice JavaScript) non funzioneranno nelle funzioni mappate. Ad esempio:
Errore: questo codice non funziona.
Editor di codice (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()))
Questo errore un po' criptico è dovuto al processo utilizzato da Earth Engine per trasformare questo codice in un insieme di istruzioni che possono essere eseguite sui server Google. Le funzioni e le strutture di controllo lato client non possono essere utilizzate per operare sull'immagine dell'argomento passata alla funzione mappata. Per evitare questo errore, evita di utilizzare funzioni lato client nelle funzioni mappate. Consulta la pagina Client e server per scoprire di più sulla distinzione tra le funzioni client e server.
Le funzioni mappate hanno requisiti aggiuntivi. Ad esempio, le funzioni mappate devono restituire qualcosa:
Errore: questo codice non funziona.
Editor di codice (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 soluzione forse più ovvia è restituire qualcosa. Tuttavia, non può restituire qualsiasi tipo
di elemento. Nello specifico, le funzioni mappate su un ImageCollection
o
FeatureCollection
devono restituire un Image
o
Feature
. Ad esempio, non puoi restituire una data da una funzione mappata su un ImageCollection
:
Errore: questo codice non funziona.
Editor di codice (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())
Per evitare questo problema, restituisci l'immagine di input con un nuovo set di proprietà. Se hai bisogno di un elenco
delle date delle immagini nella raccolta, puoi utilizzare aggregate_array()
:
Soluzione: imposta una proprietà.
Editor di codice (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())
Errori procedurali
Il pattern è stato applicato a un'immagine senza bande
L'errore "Pattern 'my_band' was applied to an Image with no bands"
indica che esiste una chiamata ee.Image.select()
per un'immagine
con un elenco di bande vuoto. Ecco cosa puoi fare per risolvere il problema:
- Se l'immagine viene prodotta da una raccolta di immagini con un riduttore o
utilizzando le chiamate
first()
otoBands()
, assicurati che la raccolta di origine non sia vuota. - Se l'immagine viene prodotta da un dizionario utilizzando
ee.Dictionary().toImage()
, assicurati che il dizionario non sia vuoto. - Se l'immagine è autonoma, assicurati che contenga dati (e non sia solo
ee.Image(0)
).
Errori di scalabilità
Anche se uno script può essere sintatticamente corretto, senza errori logici e rappresentare un insieme valido di istruzioni per il server, durante la parallelizzazione e l'esecuzione del calcolo, gli oggetti risultanti potrebbero essere troppo grandi, troppo numerosi o richiedere troppo tempo per il calcolo. In questo caso, verrà visualizzato un messaggio di errore che indica che l'algoritmo non può essere scalato. Questi errori sono in genere i più difficili da diagnosticare e risolvere. Ecco alcuni esempi di questo tipo di errore:
- Il calcolo ha superato il tempo di attesa
- Troppe aggregazioni simultanee
- Limite di memoria utente superato
- Si è verificato un errore interno
Migliorare la scalabilità del codice ti consentirà di ottenere risultati più rapidamente e di migliorare anche la disponibilità delle risorse di calcolo per tutti gli utenti. Ogni tipo di errore viene discusso nelle
sezioni seguenti, dopo una breve nota su reduceRegion()
, una funzione di uso comune
nota per essere in grado di causare ogni tipo di errore di scalabilità.
reduceRegion()
Sebbene reduceRegion()
consumi avidamente pixel sufficienti per attivare un'emozionante varietà di errori, esistono anche parametri destinati a controllare il calcolo, in modo da poter superare gli errori. Ad esempio, considera la seguente
riduzione sconsigliata:
Errore: questo codice non funziona.
Editor di codice (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())
Questo esempio sciocco è solo a scopo dimostrativo. Lo scopo di questo errore è chiederti se davvero vuoi ridurre 80300348117 (ovvero 80 miliardi) di pixel. In caso contrario, aumenta scale
(dimensioni dei pixel in metri) di conseguenza o imposta bestEffort
su true per ricalcolare automaticamente una scala più grande. Per maggiori dettagli su questi parametri, consulta la pagina reduceRegion()
.
Il calcolo ha superato il tempo di attesa
Supponiamo che tu abbia bisogno di tutti questi pixel nel calcolo. In questo caso, puoi aumentare il parametro
maxPixels
per consentire il completamento del calcolo. Tuttavia, Earth Engine impiegherà un po' di tempo per completare il calcolo. Di conseguenza, potrebbe essere generato un
errore "Il calcolo ha superato il tempo limite":
Risultato negativo: non farlo.
Editor di codice (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())
Questo errore indica che Earth Engine ha aspettato circa cinque minuti prima di interrompere il calcolo. L'esportazione consente a Earth Engine di eseguire il calcolo in un ambiente con tempi di esecuzione consentiti più lunghi (ma non con più memoria). Poiché il valore restituito
da reduceRegion()
è un dizionario, puoi utilizzare il dizionario per impostare
le proprietà di una funzionalità con geometria null:
Ottimo: utilizza Export
.
Editor di codice (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()
Troppe aggregazioni simultanee
La parte "aggregazioni" di questo errore si riferisce a operazioni distribuite su più macchine (ad esempio riduzioni che interessano più riquadri). Earth Engine ha imposto dei limiti per impedire l'esecuzione di troppe aggregazioni contemporaneamente. In questo esempio, l'errore "Troppe aggregazioni simultanee" viene attivato da una riduzione all'interno di una mappa:
Risultato negativo: non farlo.
Editor di codice (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())
Supponendo che lo scopo di questo codice sia ottenere le statistiche delle immagini per ogni immagine, una possibile soluzione è Export
il risultato. Ad esempio, utilizzando il fatto
che un ImageCollection
è anche un FeatureCollection
, i
metadati associati alle immagini possono essere esportati come tabella:
Ottimo: utilizza Export
.
Editor di codice (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()
Limite di memoria utente superato
Un modo per eseguire il parallelismo degli algoritmi in Earth Engine è suddividere gli input in riquadri, eseguire lo stesso calcolo separatamente su ogni riquadro e poi combinare i risultati. Di conseguenza, tutti gli input necessari per calcolare un riquadro di output devono essere memorizzati in memoria. Ad esempio, se l'input è un'immagine con molti canali, potrebbe essere necessaria molta memoria se tutti i canali vengono utilizzati nel calcolo. Per dimostrare, questo esempio utilizza troppa memoria forzando (inutilmente) un'intera raccolta di immagini in un riquadro:
Risultato negativo: non farlo.
Editor di codice (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())
Questo codice molto errato dimostra un motivo per cui non utilizzare gli array, a meno che non sia assolutamente necessario (vedi anche la sezione "Evita di convertire il tipo inutilmente"). Quando la raccolta viene convertita in un array gigantesco, l'array deve essere caricato in memoria contemporaneamente. Poiché si tratta di una serie di immagini che si estende per un lungo periodo di tempo, l'array è di grandi dimensioni e non può essere memorizzato nella memoria.
Una possibile soluzione è impostare il parametro tileScale
su un valore più alto. Valori più elevati di tileScale generano riquadri più piccoli di un fattore
tileScale^2
. Ad esempio, quanto segue consente il completamento del calcolo:
Editor di codice (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())
Tuttavia, la soluzione più preferita è non utilizzare gli array inutilmente, in modo da non dover fare nulla con tileScale
:
Ottimo: evita gli array.
Editor di codice (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 meno che non sia necessario per risolvere un errore di memoria, non dovresti impostare tileScale
perché i riquadri più piccoli comportano anche un maggiore overhead di parallelizzazione.
Errori interni
Potresti visualizzare un errore simile al seguente:
Se ricevi questo errore, fai clic sul link "Segnala errore" visualizzato nella console Editor di codice JavaScript. Puoi anche inviare un feedback dal pulsante Guida. Questo errore può essere causato da errori logici nello script che diventano evidenti solo in fase di esecuzione o da un problema con il funzionamento interno di Earth Engine. In entrambi i casi, l'errore non fornisce informazioni e deve essere segnalato per poter essere corretto.
Gli errori interni includono un ID request
, come il seguente:
Queste stringhe fungono da identificatori univoci per aiutare il team di Earth Engine a identificare problemi specifici. Includi questa stringa nelle segnalazioni di bug.
Metodi di debug
Hai codificato l'analisi, l'hai eseguita e hai visualizzato un errore. Ti chiedi cosa fare adesso? Questa sezione descrive tecniche di debug generali per isolare il problema e risolverlo.
Controllare le variabili e i livelli della mappa
Supponiamo che tu abbia un'analisi molto complessa che genera un errore. Se non è evidente la provenienza dell'errore, una buona strategia iniziale è stampare o visualizzare gli oggetti intermediari e ispezionarli per assicurarti che la struttura dell'oggetto sia coerente con la logica dello script. In particolare, puoi controllare i valori dei pixel dei livelli aggiunti alla mappa con gli strumenti di ispezione di Code Editor o geemap. Se stampi qualcosa, assicurati di espandere le relative proprietà con i zippy (▶). Ecco alcuni aspetti da controllare:
- Nomi dei gruppi. I nomi delle bande di immagini corrispondono al tuo codice?
- Valori dei pixel. I dati hanno l'intervallo corretto? È mascherato in modo appropriato?
- Null. Ci sono valori null che non dovrebbero essere presenti?
- Dimensioni. La dimensione è zero quando non dovrebbe?
aside()
Può essere oneroso inserire ogni passaggio intermedio di un'analisi in una variabile in modo che possa essere stampato e controllato. Per stampare i valori intermedi di una lunga catena di chiamate di funzione, puoi utilizzare il metodo aside()
. Ad esempio:
Editor di codice (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() )
Ricorda che aside(print)
(editor di codice JavaScript) e
aside(display)
(geemap di Python) chiamano funzioni lato client e
continueranno a non riuscire nelle funzioni mappate. Puoi anche utilizzare aside
con funzioni definite dall'utente. Ad esempio:
Editor di codice (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
Esecuzione di una funzione su first()
La stampa e la visualizzazione sono utili per il debug, se disponibili, ma quando esegui il debug di una funzione mappata su una raccolta, non puoi stampare nella funzione, come descritto nella sezione sulle funzioni mappate. In questo caso, è utile isolare gli elementi problematici nella raccolta e testare la funzione mappata su un singolo elemento. Quando testi la funzione senza mapparla, puoi utilizzare le istruzioni di stampa per comprendere il problema. Considera l'esempio seguente.
Errore: questo codice non funziona.
Editor di codice (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())
Per eseguire il debug, è utile esaminare l'errore. Fortunatamente, questo utile messaggio di errore
ti informa che esiste un problema con la funzionalità ID=2
. Per approfondire, è utile eseguire un po' di refactoring del codice. Nello specifico, non puoi
avere istruzioni di stampa nella funzione quando è mappata su una raccolta, come descritto in
questa sezione. L'obiettivo del debug è isolare la funzionalità problematica ed eseguire la funzione con alcune istruzioni di stampa al suo interno. Con la stessa immagine e le stesse funzionalità utilizzate
in precedenza:
Editor di codice (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
Ora, poiché la funzione viene eseguita solo su una funzionalità, puoi inserire una chiamata di stampa ("display" per
geemap di Python). Esamina l'oggetto stampato per scoprire (azzeccato!) che l'oggetto
restituito da reduceRegion()
contiene valori null per ogni banda. Questo spiega perché la
divisione non va a buon fine: perché non puoi dividere null per null. Perché è nullo in primo luogo?
Per effettuare accertamenti, aggiungi l'immagine di input e l'elemento non valido alla mappa e centrala sull'elemento non valido. In questo modo, scopri che il problema è dovuto al fatto che il punto si trova al di fuori
dei limiti dell'immagine. In base a questa scoperta, il codice sottoposto a debug è:
Editor di codice (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
Il profiler fornisce informazioni sul tempo EECU e sull'utilizzo della memoria (per algoritmo e asset) derivanti dal calcolo eseguito quando è abilitato. Cerca le voci nella parte superiore del profiler per informazioni sulle operazioni che richiedono più risorse. Per gli script di lunga durata o inefficaci, le voci nella parte superiore del profiler forniscono indizi su dove concentrare gli sforzi per ottimizzarli. Nota importante: il profiler stesso influisce sulle prestazioni dello script, pertanto devi eseguirlo solo se necessario.