Haoran Wu
The present page summaries most frequently used functions in Google Earth Engine (GEE). To get start with GEE, there are lots of introductory guides available online, which includes the Beginner’s Cookbook provided by Earth Engine Team. The following steps are simply one way to get started:
This should not take too much time (ideally 1-2 days). After going through this guide, we get familiar with the interface and basic functions. A good time to summarise them.
A typical GEE script goes like this:
/* =================================================================================
* CALCULATE MAXIMAL AND MINIMAL VALUE OF NDVI
* =================================================================================
* DATE:
*
* 11:06 GMT 13/11/2022
*
* =================================================================================
* AUTHOR:
*
* Haoran Wu, [email protected]
* Wolfson College @ School of Geography and the Environment | Univeristy of Oxford
*
* =================================================================================
* OVERVIEW:
*
* The present script calculates the maximal and minimal values of NDVI in 1992.
* Data used in this process comes from GIMMS NDVI From AVHRR Sensors (3rd
* Generation).
*
* =================================================================================
*/
// =================================================================================
// PARAMETER SEETINGS
//
// =================================================================================
var focus_year = 1991; // Year under consideration.
// =================================================================================
// MAIN PROCEDURE
//
// Do NOT edit this script past this point unless you know what you are doing
// =================================================================================
// Step 0: Import Packages (Sometimes we need to import external JavaScript functions)
// to perform advanced algorithms. A typical example is:
// // var oeel=require('users/OEEL/lib:loadAll');
// // // import functions from Open Earth Engine Library (OEEL)
// ·················································································
// ************ Step1: Import Data ************
// ·················································································
var start_date = ee.Number(focus_year).format('%.0f').cat("-01-01");
// We get "1991-01-01"
var end_date = ee.Number(focus_year).format('%.0f').cat("-12-31");
// We get "1991-12-31"
var ndvi_1year = ee.ImageCollection("NASA/GIMMS/3GV0")
.filterDate(start_date, end_date) // Filter the date
.select("ndvi"); // Select band 'ndvi'
// Import GIMMS NDVI From AVHRR Sensors (3rd Generation) data set
// See https://developers.google.com/earth-engine/datasets/catalog/NASA_GIMMS_3GV0 for data description
// Apply water mask
var water_dataset = ee.Image('MODIS/MOD44W/MOD44W_005_2000_02_24'); // Import water mask data set
var waterMask = water_dataset.select('water_mask').multiply(-1).add(1); // Create water mask
ndvi_1year = ndvi_1year.map(function(waterMask){ // Use water mask
return function(image){
return image.updateMask(waterMask);
};
}(waterMask));
// Check the imported data
print("The Collection of Images: ", ndvi_1year);
print("The First Image: ", ndvi_1year.first());
// ·················································································
// ************ Step2: Data Processing ************
// ·················································································
var ndvi_1year_max = ndvi_1year.max(); // Calculate maximal NDVI
var ndvi_1year_min = ndvi_1year.min(); // Calculate minimal NDVI
// ·················································································
// ************ Step3: Data Visualisation ************
// ·················································································
var minNDVIVisParam = {"opacity":1,"bands":["ndvi"],"min":-2.796297542978978,"max":1.8065977834391576,"palette":["fff9b4","ecef16","eb991f","ef620f","f30d02"]};
var maxNDVIVisParam = {"opacity":1,"bands":["ndvi"],"min":-2.796297542978978,"max":1.8065977834391576,"palette":["fff9b4","ecef16","eb991f","ef620f","f30d02"]};
// Define Visualisation Parameters
Map.addLayer(ndvi_1year_min, minNDVIVisParam, "NDVI_min"); // Mapping minimal NDVI
Map.addLayer(ndvi_1year_max, maxNDVIVisParam, "NDVI_max"); // Mapping maximal NDVI
The script is divided into several parts:
Header: The first part of a formal script is usually all commented out, and contains information such as script name, date created, author (s), contact information, short description, etc.
Parameter Settings: List parameters that are used in the script before the main algorithm is executed. Separating parameters from the main algorithm is a good way to improve code readability
Import and Filter the Data:
Import Data: Data can be usually found using Earth Engine Data Catalog or simply the search box at the top of Earth Engine Code Editor. Code used to import data can always be found for given data sets.
Filter Data: Data are filtered either to restrict our attention on a specific time period or a region, or for quality control.
Processing Data: Main procedure to process the data and derive the results.
Visualisation: Usually map the results around the world.
The first reason to filter the data is that our research question only concerns with specific time periods, regions, or bands.
(1) Filter by a Data Range
var ndvi_5year = ee.ImageCollection("NASA/GIMMS/3GV0")
.filterDate('1995-01-01', '1999-12-31');
(2) Filter by a Calendar Range
var ndvi_5yearJuly = ee.ImageCollection("NASA/GIMMS/3GV0")
.filterDate('1995-01-01', '1999-12-31')
.filter(ee.Filter.calendarRange(7,7,'month'));
// July 1995, July 1996, July 1997, July 1998, and July 1999
(3) Filter by a Region (Clip the Image)
We use function ee.Image.clip
rather than ee.ImageCollection.filterBounds
(use this link to see why).
var london =
/* color: #0b4a8b */
/* displayProperties: [
{
"type": "rectangle"
}
] */
ee.Geometry.Polygon(
[[[-0.6990834762355069, 51.756266246510734],
[-0.6990834762355069, 51.17450747305587],
[0.38856300813949307, 51.17450747305587],
[0.38856300813949307, 51.756266246510734]]], null, false);
var ndvi_london = ee.ImageCollection("NASA/GIMMS/3GV0").map(function(geometry){
return function(image){
return image.clip(geometry);
};
}(london));
The syntax of map function might be a challenge for beginners. I also expand on that in the next episode.
(4) Select Bands
var ndvi = ee.ImageCollection("NASA/GIMMS/3GV0").select(["ndvi"])
// Select band "ndvi" and discard other bands
This might include cloud removal, water mask, etc. Beginners might find the following codes hard to interpret due to relatively complicated mechanisms of map
function. I will expand on this in the next post.
// Function to remove clouds for Landsat 8 data set
// Data description page: https://developers.google.com/earth-engine/datasets/catalog/LANDSAT_LC08_C02_T1_L2
// NOTE: For different data set, this function can be different; hence it is important
// to understand the mechanism
var maskL8sr = function(image) {
// * First, look up the band description page, https://developers.google.com/earth-engine/datasets/catalog/LANDSAT_LC08_C02_T1_L2#bands.
// * We found that pixel quality information is stored in band 'QA_PIXEL'.
// Get the pixel QA band.
var qa = image.select('QA_PIXEL');
// * We then collpase "Bitmask for QA_PIXEL" and see that:
// * Bit 2: Cirrus (high confidence)
// * Bit 3: Cloud
// * Bit 4: Cloud Shadow
// Bits 2, 3, and 4 are cirrus, cloud, and cloud shadow.
var cirrusBitMask = 1 << 2;
var cloudBitMask = 1 << 3;
var cloudshadowBitMask = 1 << 4;
// Mechanism: 2^4 (decimal) = 16 (decimal) = 1000 (binary)
// hence, bitwise AND operations could help to select the 4th bit
// All flags should be set to zero, indicating clear conditions.
var mask = qa.bitwiseAnd(cirrusBitMask).eq(0) // bit 2 == 0
.and(qa.bitwiseAnd(cloudBitMask).eq(0)) // bit 3 == 0
.and(qa.bitwiseAnd(cloudshadowBitMask).eq(0)); // bit 4 == 0
// Return the masked image, scaled to TOA reflectance, without the QA bands.
return image.updateMask(mask)
.copyProperties(image, ["system:time_start"]);
// * Mechanism of Masks:
// * The value of mask images should be either 0 or non-zero (usually 1)
// * Function `updateMask` masks all positions where the value of mask image is non-zero
// * As a result, only those positions with the value of mask image being 0 are preserved
};
var landsat8 = ee.ImageCollection("LANDSAT/LC08/C02/T1_L2").map(maskL8sr);
(2) Water Mask
var water_dataset = ee.Image('MODIS/MOD44W/MOD44W_005_2000_02_24');
var waterMask = water_dataset.select('water_mask').multiply(-1).add(1);
var ndvi = ee.ImageCollection("NASA/GIMMS/3GV0").map(function(mask){
return function(image){
return image.updateMask(mask);
};
}(waterMask));
(3) Filter by Metadata
This is less frequently used. If the data quality of an image if shown in the metadata of an image collection, then it is possible to filter the data based on the corresponding property.
// Reference: https://code.earthengine.google.com/4c7fa899a2faa9e6b732d6acfcd3da5a
var S2_2015 = ee.ImageCollection("COPERNICUS/S2_SR")
.filterMetadata('NODATA_PIXEL_PERCENTAGE', 'less_than', 10);
The most important thing for data processing is to distinguish which function is for ee.ImageCollection
and which is for ee.Image
, otherwise you will get error like “XXX is not a function”.
If a function for ee.Image
class should be used for an object of ee.ImageCollection
class, then we must use map function. As mentioned before, I will go through details in the next episode.
Another important concept is “reducer”. A reducer applied to an object of ee.ImageCollection
will be applied to all of the images in the collection. A reducer applied to an object of ee.Image
will be applied to all of the bands in the image.
Here I list some important functions for basic mathematical operations. Note that all these functions are for objects of ee.Image
class.
// Import data
var ndvi = ee.ImageCollection("NASA/GIMMS/3GV0");
// Function to get the index-th image of an image collection
var img_get = function(imgcoll, index){
// imgcoll - image collection
// index - a number
return ee.Image(imgcoll.toList(imgcoll.size()).get(index));
};
var image1 = img_get(ndvi, 0); // Get the first image
var image2 = img_get(ndvi, 1); // Get the second image
// Arithmetic Operations
image1.add(image2); // image1 + image2
image1.subtract(image2); // image1 - image2
image1.multiply(image2); // image1 * image2
image1.divide(image2); // image1 / image2
image1.pow(image2); // imgae1 ** image2
// Relational Operations
image1.eq(image2); // image1 == image2
image1.neq(image2); // image1 != image2
image1.gt(image2); // image1 > image2
image1.gte(image2); // image1 >= image2
image1.lt(image2); // image1 < image2
image1.lte(image2); // image1 <= image2
// Logical Operations
image1.and(image2); // image1 && image2
image1.or(image2); // image1 || image2
image1.not(); // ! image1
// Advanced Operations
image1.normalizedDifference(['ndvi', 'qa']);
// (ndvi - qa)/(ndvi + qa) (Although that is meaningless)
image1.expression(
'(ndvi - qa)/(ndvi + qa)',
{ 'ndvi': ndvi.select('ndvi'), 'qa': ndvi.select('qa') }
); // (ndvi - qa)/(ndvi + qa) (Although that is meaningless)
// Rename band
// * After calculation, we usually give a name of the new band
image1.rename(["new_ndvi", "new_qa"]);
Function Map.addLayer
is most commonly used to visualise the result. Function Map.centerObject
can be used to locate to a specific region interested.
// Get first image of the image collection
var ndvi_img = ee.ImageCollection("NASA/GIMMS/3GV0").first().select("ndvi");
// Use Water Mask
var water_dataset = ee.Image('MODIS/MOD44W/MOD44W_005_2000_02_24');
var waterMask = water_dataset.select('water_mask').multiply(-1).add(1);
ndvi_img = ndvi_img.updateMask(waterMask);
// Visualisation
Map.setCenter(-1.67, 52.898, 6); // Set the location
var palettes = require('users/gena/packages:palettes');
var HSpalette = palettes.colorbrewer.YlOrRd[7];
// Set palettes (https://github.com/gee-community/ee-palettes)
var imageVisParam = {
"opacity":1, "bands":["ndvi"],
"min":-1.031950120465069,"max":1.929136434001318,
"palette": HSpalette
}; // Set visualisation parameter. It can be generated by map toolkits.
Map.addLayer(ndvi_img, imageVisParam, "NDVI Map");
I shall discuss other visualisation method such as line plots in the next post.
Next: GEE and Vegetation Ecology (II) – The .map
Function