Pierwsze kroki z Earth Engine

Ten przewodnik ma na celu szybkie rozpoczęcie programowania za pomocą interfejsu JavaScript API Earth Engine. Wprowadzenie do JavaScripta i szczegółowe ćwiczenia dotyczące interfejsu Earth Engine API znajdziesz w tych samouczkach. Zalecane style kodowania JavaScript znajdziesz w przewodniku Google na temat stylu JavaScriptu.

Google Earth Engine umożliwia użytkownikom uruchamianie algorytmów na zdjęciach i wektora z georeferencji przechowywanych w infrastrukturze Google. Interfejs Google Earth Engine API udostępnia bibliotekę funkcji, które można stosować do danych na potrzeby wyświetlania i analizy. Katalog publicznych danych Earth Engine zawiera dużą ilość publicznie dostępnych zdjęć i zbiorów danych wektorów. Zasoby prywatne można też tworzyć w folderach osobistych użytkowników.

Jak korzystać z tych dokumentów

Dokumentacja Earth Engine jest przeznaczona dla osób znających analizę danych geoprzestrzennych. Dokumenty są uporządkowane głównie według typu danych. Na przykład w panelu nawigacyjnym po lewej stronie znajdują się linki do sekcji lub stron z ważnymi typami danych, takich jak Image, ImageCollection, Feature, FeatureCollection, Geometry, Reducer, Chart, JoinArray. Ten przewodnik zawiera tylko tyle informacji o tych typach, aby można było zacząć. Znajdziesz tu też sekcje dotyczące systemów uczących się, algorytmów specjalistycznych lub algorytmów związanych z konkretnym czujnikiem (np. algorytmów Landsat), aplikacji publicznych, zarządzania danymi (zasobami) oraz ważne informacje o działaniu Earth Engine od wewnątrz. Zanim zaczniesz, zacznij od tego.

Edytor kodu

Edytor kodu to interaktywne środowisko do tworzenia aplikacji Earth Engine (ryc. 1). W panelu środkowym znajduje się edytor kodu JavaScript. Nad edytorem znajdują się przyciski do zapisywania bieżącego skryptu, jego uruchamiania i czyszczenia mapy. Przycisk Pobierz link generuje w pasku adresu unikalny adres URL skryptu. Mapa w dolnym panelu zawiera warstwy dodane przez skrypt. U góry znajduje się pole wyszukiwania zbiorów danych i miejsc. Panel po lewej stronie zawiera przykłady kodu, zapisane skrypty, referencje do interfejsu API z możliwością wyszukiwania oraz menedżera zasobów do zarządzania danymi prywatnymi. W panelu po prawej stronie znajduje się: inspekcja do wysyłania zapytań do mapy, konsola wyjściowa i menedżer do zarządzania długotrwałymi zadaniami. Przycisk pomocy w prawym górnym rogu zawiera linki do tego przewodnika i innych zasobów pomocy. Więcej informacji znajdziesz w przewodniku po Edytorze koduprzewodniku pomocy.

Edytor kodu
Rysunek 1. Edytora kodu Earth Engine na stronie code.earthengine.google.com

Otwieranie i uruchamianie kodu w Edytorze kodu

Poniżej znajdziesz instrukcje otwierania Earth Engine i uruchamiania skryptu niestandardowego, który wyświetla obraz. Aby uzyskać najlepsze wyniki, zainstaluj najnowszą wersję przeglądarki Google Chrome, którą można pobrać tutaj.

  1. Otwórz Edytor kodu Earth Engine pod adresem code.earthengine.google.com.
  2. Otwórz kartę Skrypty, która znajduje się po lewej stronie Edytora kodu. Znajdziesz tam zbiór przykładowych skryptów, które umożliwiają dostęp do danych Earth Engine, ich wyświetlanie i analizowanie.
  3. W sekcji „Zbiór obrazów” wybierz przykład „Filtrowany obraz złożony”. W konsoli środkowej pojawi się skrypt. Aby wykonać skrypt, kliknij przycisk Uruchom. Przykładowa kompozycja z filtrem wybiera obrazy Landsat 7, które nakładają się na siebie lub znajdują się w granicach Kolorado i Utah. Następnie wyświetla kompozycję kolorów wybranych obrazów. Przykłady pokazują stosowanie popularnych metod, takich jak filter(), clip()Map.addLayer().

Struktury danych Earth Engine

Dwie podstawowe struktury danych geograficznych w Earth Engine to: ImageFeature, które odpowiadają odpowiednio typom danych rastrowych i wektorów. Obrazy składają się z pasm i słownika właściwości. Cechy składają się z Geometry i słownika właściwości. Grupa obrazów (np. ciąg czasowy obrazów) jest obsługiwana przez ImageCollection. Kolekcja funkcji jest obsługiwana przez FeatureCollection. Inne podstawowe struktury danych w Earth Engine to Dictionary, List, Array, Date, NumberString (więcej informacji o podstawowych typach danych znajdziesz w tym samouczku). Pamiętaj, że są to obiekty po stronie serwera, które nie są modyfikowane w taki sam sposób jak obiekty JavaScript po stronie klienta (dowiedz się więcej).

algorytmy Earth Engine;

Operacje w interfejsie API możesz wykonywać na kilka sposobów:

  • wywoływanie metod dołączonych do obiektów;
  • wywoływanie algorytmów;
  • Wywoływanie funkcji edytora kodu.
  • definiowanie nowych funkcji;

Na karcie Dokumenty w Edytorze kodu znajdziesz listę metod każdej klasy interfejsu API. Na przykład klasa Image ma metodę add():

Edytor kodu (JavaScript)

var image3 = image1.add(image2);

Ta metoda dodaje pasma image2 do pasm image1. Kategoria ee.Algorithms zawiera listę obecnie obsługiwanych algorytmów do przetwarzania specjalistycznego lub specyficznego dla danej dziedziny. Aby na przykład utworzyć warstwy topograficzne na podstawie wejściowego cyfrowego modelu rzeźby terenu (DEM):

Edytor kodu (JavaScript)

var terrainImage = ee.Algorithms.Terrain(dem);

Funkcje specyficzne dla edytora kodu to metody MapExport, które kontrolują sposób dodawania warstw do panelu mapy lub eksportowania ich na Dysk Google. Funkcje można też tworzyć w JavaScript za pomocą

Edytor kodu (JavaScript)

var myFunction = function(args) {
  // do something
  return something;
};

Jak pokazano w sekcji Mapowanie, funkcje definiowane przez użytkownika są przydatne do tworzenia niestandardowych funkcji lub modyfikowania elementów kolekcji za pomocą:

Edytor kodu (JavaScript)

var collection2 = collection1.map(aFunction);

W kolejnych sekcjach omawiamy te zagadnienia w ramach kilku prostych przypadków użycia.

„Hello world!” JavaScript

Wyświetlanie informacji w konsoli to podstawowe zadanie polegające na uzyskiwaniu informacji o obiekcie, wyświetlaniu wyników obliczeń liczbowych, wyświetlaniu metadanych obiektu lub pomocy w debugowaniu. Znane wszystkim „Hello World!” w Edytorze kodu wygląda tak:

Edytor kodu (JavaScript)

print('Hello world!');

Skopiuj ten wiersz do edytora kodu i kliknij Uruchom. Pamiętaj, że dane wyjściowe są wyświetlane na karcie Konsola po prawej stronie edytora kodu. Oto przykład bardziej odpowiedni do teledetekcji: wypisuje on metadane obrazu Landsat 8:

Edytor kodu (JavaScript)

print(ee.Image('LANDSAT/LC08/C02/T1_TOA/LC08_044034_20140318'));

Uważnie sprawdź dane wyjściowe w konsoli, aby zobaczyć metadane dostępne dla zdjęć Landsat.

Dodawanie danych do mapy

Oprócz drukowania informacji na konsoli możesz dodawać dane do Map, aby wizualizować dane geograficzne. Użyj do tego Map.addLayer(). W tym przykładzie instancja Image jest tworzona (sposób znajdowania tych obrazów opisujemy później) za pomocą ee.Image(), dodawana do mapy za pomocą Map.addLayer(), a mapa jest wyśrodkowana nad obrazem:

Edytor kodu (JavaScript)

// Load an image.
var image = ee.Image('LANDSAT/LC08/C02/T1_TOA/LC08_044034_20140318');

// Center the map on the image.
Map.centerObject(image, 9);

// Display the image.
Map.addLayer(image);

Drugi parametr Map.centerObject() to poziom powiększenia, gdzie większe liczby oznaczają większą skalę (większe powiększenie). Parametry funkcji Map są szczegółowo opisane w dokumentacji interfejsu API, do której można przejść z karty Dokumenty. Jeśli wygląd obrazu jest niezadowalający, skonfiguruj parametry wyświetlania za pomocą dodatkowego argumentu w funkcji Map.addLayer(). Przykład:

Edytor kodu (JavaScript)

// Load the image from the archive.
var image = ee.Image('LANDSAT/LC08/C02/T1_TOA/LC08_044034_20140318');

// Define visualization parameters in an object literal.
var vizParams = {bands: ['B5', 'B4', 'B3'], min: 0.02, max: 0.4, gamma: 1.3};

// Center the map on the image and display.
Map.centerObject(image, 9);
Map.addLayer(image, vizParams, 'Landsat 8 false color');

Zwróć uwagę, że parametry wizualizacji są zdefiniowane przez literał obiektu, który zawiera listę pasm do wyświetlenia, minimalną i maksymalną wartość odbicia oraz wartość gamma. (więcej informacji o pasmach Landsat znajdziesz tutaj). Więcej informacji o wizualizacji obrazów znajdziesz tutaj.

Aby dodać do mapy obiekty i zbiory obiektów, użyj Map.addLayer(). Na przykład:

Edytor kodu (JavaScript)

var counties = ee.FeatureCollection('TIGER/2018/Counties');
Map.addLayer(counties, {}, 'counties');

Wyszukiwanie obrazów, kolekcji obrazów i zbiorów cech

Zdjęcia, kolekcje zdjęć i zbiory cech można znaleźć, wyszukując je w Earth Engine Data Catalog. Na przykład wpisanie „Landsat 8” w polu wyszukiwania spowoduje wyświetlenie na liście zbiorów danych rastrowych wyników wyszukiwania zawierających „Landsat 8”. (pełna lista zbiorów danych Earth Engine znajduje się w Earth Engine Data Catalog). Kliknij nazwę zbioru danych, aby wyświetlić jego krótki opis, informacje o czasowej dostępności, dostawcę danych i identyfikator zbioru. Kliknij przycisk Importuj, aby utworzyć automatycznie sekcję Importy u góry skryptu z wartością zmiennej dla tej kolekcji.

Możesz też skopiować identyfikator kolekcji i wklejć go w kodzie. Na przykład: wybierz wynik TOA poziomu 1 z wyszukiwania „Landsat 8” i skopiuj identyfikator w ten sposób:

Edytor kodu (JavaScript)

var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA');

Jest to kolekcja wielu zdjęć obejmujących powierzchnię lądową Ziemi, więc znalezienie pojedynczego obrazu w zbiorze wymaga odfiltrowania wyników wyszukiwania. Zbiór obrazów można też zredukować do pojedynczego obrazu, stosując techniki kompozytowania i mozaikowania. Więcej informacji o filtrowaniu i kompozytowaniu (patrz Zmniejsz) znajdziesz w kolejnych sekcjach.

Zbiory funkcji są też dostępne w Data Catalog. Ich reprezentacja jest mniejsza niż w przypadku kolekcji obrazów, ale znajdziesz wśród nich między innymi granice międzynarodowe, spisu ludności, zlewiska i obszarów chronionych. Więcej informacji o importowaniu własnych zbiorów danych wektorów znajdziesz tutaj.

Filtrowanie i sortowanie

Aby ograniczyć liczbę wyników, często trzeba filtrować kolekcję według miejsca lub czasu. Rozważ na przykład posortowanie kolekcji ujęć Landsat 8, aby znaleźć ujęcie San Francisco bez chmur. Najpierw musisz określić region zainteresowania. W tym celu często przydaje się punkt. Aktywuj kartę Inspektor po prawej stronie edytora kodu i kliknij w pobliżu środka obszaru zainteresowania, skopiuj współrzędne z karty Inspektor, a potem utwórz Point za pomocą:

Edytor kodu (JavaScript)

var point = ee.Geometry.Point(-122.262, 37.8719);

Utwórz daty rozpoczęcia i zakończenia:

Edytor kodu (JavaScript)

var start = ee.Date('2014-06-01');
var finish = ee.Date('2014-10-01');

Filtruj kolekcję Landsat 8 za pomocą punktu i daty, a potem sortuj za pomocą właściwości metadanych (odkrytej podczas sprawdzania metadanych sceny Landsat 8):

Edytor kodu (JavaScript)

var filteredCollection = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA')
  .filterBounds(point)
  .filterDate(start, finish)
  .sort('CLOUD_COVER', true);

Ta kolekcja może być bezpiecznie wydrukowana i przeanalizowana. (jeśli kolekcja zawiera zbyt wiele obrazów, jej drukowanie będzie bardzo powolne, przekroczy limit czasu lub zwróci błąd). Zwróć uwagę, że obrazy w zbiorze to List przechowywane w właściwości „features” obiektu ImageCollection. Identyfikator dowolnego obrazu w kolekcji można skopiować do konstruktora Image, jak wyżej. Możesz też pobrać pierwsze zdjęcie (z najmniejszą pokrywą chmur):

Edytor kodu (JavaScript)

var first = filteredCollection.first();

Korzystaj z pełnej funkcjonalności filtrowania Earth Engine za pomocą funkcji filter(), podając jako argument element ee.Filter. (metody filterBounds()filterDate() użyte powyżej to skróty). Na przykład poniższy kod tworzy wyrażenie Filter, używa go do filtrowania wyrażenia FeatureCollection i wyświetla wynik:

Edytor kodu (JavaScript)

// Load a feature collection.
var featureCollection = ee.FeatureCollection('TIGER/2016/States');

// Filter the collection.
var filteredFC = featureCollection.filter(ee.Filter.eq('NAME', 'California'));

// Display the collection.
Map.setCenter(-119.604, 37.798, 6);
Map.addLayer(filteredFC, {}, 'California');

Obliczanie pasm

Wykonywanie operacji matematycznych na obrazach za pomocą metod Image. Mogą to być rekombinacje pasm (indeksy widmowe), różnice obrazów lub operacje matematyczne, takie jak mnożenie przez stałą. Na przykład można obliczyć różnicę między obrazami z znormalizowanym różnicowym wskaźnikiem wegetacji (NDVI) z 20-letnim okresem między nimi:

Edytor kodu (JavaScript)

// This function gets NDVI from Landsat 5 imagery.
var getNDVI = function(image) {
  return image.normalizedDifference(['B4', 'B3']);
};

// Load two Landsat 5 images, 20 years apart.
var image1 = ee.Image('LANDSAT/LT05/C02/T1_TOA/LT05_044034_19900604');
var image2 = ee.Image('LANDSAT/LT05/C02/T1_TOA/LT05_044034_20100611');

// Compute NDVI from the scenes.
var ndvi1 = getNDVI(image1);
var ndvi2 = getNDVI(image2);

// Compute the difference in NDVI.
var ndviDifference = ndvi2.subtract(ndvi1);

Zwróć uwagę, że w tym przykładzie użyto zdefiniowanej przez użytkownika zmiennej function. Więcej informacji o funkcjach znajdziesz w następnej sekcji.

Mapowanie (co zrobić zamiast pętli for)

Aby przejrzeć elementy w kolekcji, użyj elementu map(). (pętle for nie są najlepszym sposobem na wykonywanie tych czynności w Earth Engine i należy ich unikać). Funkcję map() można zastosować do argumentu ImageCollection, FeatureCollection lub List i przyjmuje ona argument function. Argument funkcji to element kolekcji, do której jest mapowana. Jest to przydatne, gdy chcesz zmodyfikować wszystkie elementy kolekcji w taki sam sposób, na przykład dodać. Na przykład ten kod dodaje pasmo NDVI do każdego obrazu w pliku ImageCollection:

Edytor kodu (JavaScript)

// This function gets NDVI from Landsat 8 imagery.
var addNDVI = function(image) {
  return image.addBands(image.normalizedDifference(['B5', 'B4']));
};

// Load the Landsat 8 TOA data, filter by location and date.
var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA')
  .filterBounds(ee.Geometry.Point(-122.262, 37.8719))
  .filterDate('2014-06-01', '2014-10-01');

// Map the function over the collection.
var ndviCollection = collection.map(addNDVI);

Innym częstym zadaniem jest dodawanie nowej właściwości (czyli „atrybutu” lub „pola”) do funkcji w FeatureCollection. W tym przykładzie nowa usługa to obliczenie uwzględniające 2 dotychczasowe atrybuty:

Edytor kodu (JavaScript)

// This function creates a new property that is the sum of two existing properties.
var addField = function(feature) {
  var sum = ee.Number(feature.get('property1')).add(feature.get('property2'));
  return feature.set({'sum': sum});
};

// Create a FeatureCollection from a list of Features.
var features = ee.FeatureCollection([
  ee.Feature(ee.Geometry.Point(-122.4536, 37.7403),
    {property1: 100, property2: 100}),
    ee.Feature(ee.Geometry.Point(-118.2294, 34.039),
    {property1: 200, property2: 300}),
]);

// Map the function over the collection.
var featureCollection = features.map(addField);

// Print a selected property of one Feature.
print(featureCollection.first().get('sum'));

// Print the entire FeatureCollection.
print(featureCollection);

Zwróć uwagę, że do użycia metody add() wymagane jest zastąpienie wartości właściwości za pomocą funkcji ee.Number, aby wartość była rozpoznawana jako liczba. Typ kolekcji można zmienić za pomocą map(). Na przykład:

Edytor kodu (JavaScript)

// This function returns the image centroid as a new Feature.
var getGeom = function(image) {
  return ee.Feature(image.geometry().centroid(), {foo: 1});
};

// Load a Landsat 8 TOA collection.
var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA')
  .filterBounds(ee.Geometry.Point(-122.262, 37.8719))
  .filterDate('2014-06-01', '2014-10-01');

// Map the function over the ImageCollection.
var featureCollection = ee.FeatureCollection(collection.map(getGeom));

// Print the collection.
print(featureCollection);

Zwróć uwagę na dodaną właściwość (foo) dla każdej funkcji utworzonej na podstawie centroidu obrazu. W ostatnim wierszu typ danych sprawia, że wynikową kolekcję można rozpoznać jako FeatureCollection.

Zmniejszanie

Zmniejszenie jest sposobem na agregowanie danych w czasie, przestrzeni, pasmach, tablicach i innych strukturach danych w Earth Engine. W interfejsie API dostępne są różne metody służące do tego celu. Na przykład, aby utworzyć kompozyt ImageCollection, użyj funkcji reduce(), aby zredukować obrazy w kolekcji do jednego obrazu. Prostym przykładem jest utworzenie średniej arytmetycznej z 5 najmniej zachmurzonych scen z zbioru Landsat 8 zdefiniowanego wcześniej:

Edytor kodu (JavaScript)

// Load a Landsat 8 TOA collection.
var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA')
  // Filter by date and location.
  .filterBounds(ee.Geometry.Point(-122.262, 37.8719))
  .filterDate('2014-01-01', '2014-12-31')
  // Sort by increasing cloudiness.
  .sort('CLOUD_COVER');

// Compute the median of each pixel for each band of the 5 least cloudy scenes.
var median = collection.limit(5).reduce(ee.Reducer.median());

Zmniejszenie jest też sposobem na uzyskanie statystyk obrazu w regionach zdefiniowanych przez Feature lub FeatureCollection. Załóżmy, że zadaniem jest obliczenie średnich wartości pikseli w obszarze zainteresowania. Do tego celu możesz użyć reduceRegion(). Na przykład:

Edytor kodu (JavaScript)

// Load and display a Landsat TOA image.
var image = ee.Image('LANDSAT/LC08/C02/T1_TOA/LC08_044034_20140318');
Map.addLayer(image, {bands: ['B4', 'B3', 'B2'], max: 0.3});

// Create an arbitrary rectangle as a region and display it.
var region = ee.Geometry.Rectangle(-122.2806, 37.1209, -122.0554, 37.2413);
Map.addLayer(region);

// Get a dictionary of means in the region.  Keys are bandnames.
var mean = image.reduceRegion({
  reducer: ee.Reducer.mean(),
  geometry: region,
  scale: 30
});

Więcej informacji o reduktorach znajdziesz w dokumentacji dotyczącej reduktorów.

Zamaskowanie

Każdy piksel w bloku ee.Image ma wartość i maskę, która może przyjmować wartości od 0 (brak danych) do 1. Zamaskowane piksele (w których maska==0) są traktowane jako brak danych. Pixele z wartością od 0 do 1 mają wartość, ale jest ona ważona przez maskę na potrzeby obliczeń liczbowych.

Za pomocą masek możesz uczynić piksele przezroczystymi lub wykluczyć je z analizy. Gdy wartość maski wynosi 0, piksele są maskowane. W kontynuacji przykładu różnicowania obrazów użyj maski, aby wyświetlić obszary zwiększonego i zmniejszonego NDVI w interwale różnicy:

// This function gets NDVI from Landsat 5 imagery.
var getNDVI = function(image) {
  return image.normalizedDifference(['B4', 'B3']);
};

// Load two Landsat 5 images, 20 years apart.
var image1 = ee.Image('LANDSAT/LT05/C02/T1_TOA/LT05_044034_19900604');
var image2 = ee.Image('LANDSAT/LT05/C02/T1_TOA/LT05_044034_20100611');

// Compute NDVI from the scenes.
var ndvi1 = getNDVI(image1);
var ndvi2 = getNDVI(image2);

// Compute the difference in NDVI.
var ndviDifference = ndvi2.subtract(ndvi1);
// Load the land mask from the SRTM DEM.
var landMask = ee.Image('CGIAR/SRTM90_V4').mask();

// Update the NDVI difference mask with the land mask.
var maskedDifference = ndviDifference.updateMask(landMask);

// Display the masked result.
var vizParams = {min: -0.5, max: 0.5, palette: ['FF0000', 'FFFFFF', '0000FF']};
Map.setCenter(-122.2531, 37.6295, 9);
Map.addLayer(maskedDifference, vizParams, 'NDVI difference');

W tym przykładzie maska różnicy NDVI jest aktualizowana przez maskę gruntu z wartością updateMask(). W przypadku maski różnicy NDVI, gdy jej wartość jest różna od zera, maska pikseli różnicy NDVI jest ustawiana na maskę lądu.

Maskowanie jest też przydatne do wykluczania danych z analizy. Rozważ przykład reduceRegion() z sekcji Zmniejszanie. Załóżmy, że zadaniem jest obliczenie sezonowej średniej NDVI dla okręgu Santa Clara w Kalifornii, z wyłączeniem pikseli z chmurami. Ten przykład pokazuje kilka koncepcji: filtrowanie, mapowanie, zmniejszanie i użycie maski chmury:

Edytor kodu (JavaScript)

// This function gets NDVI from a Landsat 8 image.
var addNDVI = function(image) {
  return image.addBands(image.normalizedDifference(['B5', 'B4']));
};

// This function masks cloudy pixels.
var cloudMask = function(image) {
  var clouds = ee.Algorithms.Landsat.simpleCloudScore(image).select(['cloud']);
  return image.updateMask(clouds.lt(10));
};

// Load a Landsat collection, map the NDVI and cloud masking functions over it.
var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA')
  .filterBounds(ee.Geometry.Point([-122.262, 37.8719]))
  .filterDate('2014-03-01', '2014-05-31')
  .map(addNDVI)
  .map(cloudMask);

// Reduce the collection to the mean of each pixel and display.
var meanImage = collection.reduce(ee.Reducer.mean());
var vizParams = {bands: ['B5_mean', 'B4_mean', 'B3_mean'], min: 0.02, max: 0.4};
Map.addLayer(meanImage, vizParams, 'mean');

// Load a region in which to compute the mean and display it.
var counties = ee.FeatureCollection('TIGER/2018/Counties');
var santaClara = ee.Feature(counties.filter(ee.Filter.eq('NAME', 'Santa Clara')).first());
Map.addLayer(santaClara);

// Get the mean of NDVI in the region.
var mean = meanImage.select(['nd_mean']).reduceRegion({
  reducer: ee.Reducer.mean(),
  geometry: santaClara.geometry(),
  scale: 30
});

// Print mean NDVI for the region.
mean.get('nd_mean').evaluate(function(val){
  print('Santa Clara spring mean NDVI:', val);
});