1 of 60

Tour of the Earth Engine API

Nick Clinton, nclinton@google.com �Earth Engine Developer Relations

2 of 60

Background

3 of 60

Goodchild et al. (2012):

“The supply of geographic information from satellite-based and ground-based sensors has expanded rapidly, encouraging belief in a new, fourth, or “big data,” paradigm of science that emphasizes international collaboration, data-intensive analysis, huge computing resources, and high-end visualization.

4 of 60

Source: NASA

5 of 60

Google Mission Statement

"To organize the world's information and make it universally accessible and useful."

6 of 60

-Jim Gray (1944-2007)

Often it turns out to be more efficient to move the questions than to move the data.

7 of 60

8 of 60

Objectives of Google Earth Engine

Make substantive progress on global challenges that involve large geospatial datasets. Do things at Google scale that no one else can do.

  • Develop the world’s most advanced geospatial processing platform
  • Push the edge of the envelope for big data in remote sensing.
  • Enable high-impact, data-driven science.

9 of 60

10 of 60

Surface water occurrence - Pekel et al., JRC

南昌

11 of 60

12 of 60

13 of 60

14 of 60

Mobile to Cloud pipeline

Fusion Table

Earth Engine

App Engine

ODK

Collect

ODK Aggregate

15 of 60

Who uses Earth Engine?

16 of 60

What can you do with Earth Engine?

17 of 60

What’s on tap?

  • Reducers
  • Joins
  • Charts
  • Arrays

18 of 60

Use the Docs!

19 of 60

Reducers

20 of 60

Reduce: Image Bands to Image

var max = image.reduce(ee.Reducer.max());

ee.Reducer

ee.Image

ee.Image

1

2

3

21 of 60

Reduce: ImageCollection to Image

ee.Reducer

var collection = ee.ImageCollection('LANDSAT/LT5_L1T_TOA');

var addNDVI = function(image) {

return image.addBands(

image.normalizedDifference(['B4', 'B3']));

};

// map

var ndviCollection = collection.map(addNDVI);

// reduce

var median = ndviCollection.reduce(ee.Reducer.median());

ee.ImageCollection

ee.Image

3

1

2

7

3

22 of 60

ImageCollection.reduce()

These reducers will NOT work in ImageCollection.reduce() since they do not have a numeric output:

ee.Reducer.frequencyHistogram()

ee.Reducer.histogram()

ee.Reducer.toList()

These reducers will NOT work in ImageCollection.reduce() without first converting each input to a 1-D Array (more on Arrays later):

ee.Reducer.covariance()

ee.Reducer.centeredCovariance()

23 of 60

Reduce: Image region to statistic

var mean = image.reduceRegion({

reducer: ee.Reducer.mean(),

geometry: region.geometry(),

scale: 30,

maxPixels: 1e9,

bestEffort: true,

});

ee.Reducer

42

region

1

8

1

5

3

1

2

7

5

ee.Image

ee.Dictionary

24 of 60

Image.reduceRegion()

These reducers will NOT work in Image.reduceRegion() without first converting the image to an Array image (more on Arrays later):

ee.Reducer.centeredCovariance()

ee.Reducer.covariance()

25 of 60

Reduce: Neighborhood operations

var texture = naipNDVI.reduceNeighborhood({

reducer: ee.Reducer.stdDev(),

kernel: ee.Kernel.circle(7), // 7 is the kernel radius in pixels

});

kernel

ee.Reducer

26 of 60

Reduce: Raster to Vector

var vectors = zones.reduceToVectors({

geometry: japan,

scale: 1000,

geometryType: 'polygon',

labelProperty: 'zone',

reducer: ee.Reducer.mean()

});

Zones (red, green, blue)

ee.Image

Vectors

ee.FeatureCollection

27 of 60

Reducing a Table

‘p1’

p2’

f1

f2

f3

...

var sum = featureCollection.reduceColumns({

reducer: ee.Reducer.sum().repeat(2),

selectors: ['p1', 'p2'],

})

[sum1, sum2]

ee.List

ee.FeatureCollection

28 of 60

Reduce: Vector to Raster

var image = features.reduceToImage({

properties: ['Census 2000 Population'],

reducer: ee.Reducer.first()

});

ee.FeatureCollection

ee.Image

29 of 60

Grouping Reducer: Zonal Statistics

var zonalStats = image.reduceRegion({

reducer: ee.Reducer.mean().group({

groupField: 1,

groupName: 'code',

}),

geometry: region.geometry(),

scale: 1000,

maxPixels: 1e8

});

Returns a Dictionary

groups: List (17 elements)

0: Object (2 properties)

code: 0

mean: -0.111

1: Object (2 properties)

code: 1

mean: -0.105

2: Object (2 properties)

code: 2

mean: 0.531

ee.Image (band 0)

ee.Image (band 1)

30 of 60

Weighted Reductions

// band 0: image data

// band 1: weights

var weightedMean = image.reduceRegion({

reducer: ee.Reducer.mean().splitWeights(),

geometry: region,

scale: 30

});

31 of 60

Linear Regression

var linearRegression = collection.reduce({

reducer: ee.Reducer.linearRegression({

numX: 2,

numY: 2

})

});

var bandNames = [['constant', 'predictor'],

['response1', 'response2']];

var lrImage = linearRegression

.select(['coefficients'])

.arrayFlatten(bandNames);

response1

response2

constant

42

13

predictor

88

216

1-axis

0-axis

ee.Array

32 of 60

Reducers galore!

ee.Reducer.allNonZero()

ee.Reducer.anyNonZero()

ee.Reducer.centeredCovariance()

ee.Reducer.count()

ee.Reducer.countDistinct()

ee.Reducer.countEvery()

ee.Reducer.covariance()

ee.Reducer.first()

ee.Reducer.frequencyHistogram()

ee.Reducer.histogram()

ee.Reducer.intervalMean({

minPercentile: 0.5,

maxPercentile: 0.95

})

ee.Reducer.linearRegression({

numX: 4,

numY: 2

})

ee.Reducer.linearFit()

ee.Reducer.max()

ee.Reducer.mean()

ee.Reducer.median()

ee.Reducer.min()

ee.Reducer.minMax()

ee.Reducer.mode()

ee.Reducer.percentile([025, 0.75])

ee.Reducer.product()

ee.Reducer.robustLinearRegression({

numX: 4,

numY: 2

})

ee.Reducer.sampleStdDev()

ee.Reducer.sampleVariance()

ee.Reducer.stdDev()

ee.Reducer.sum()

ee.Reducer.toList()

ee.Reducer.variance()

33 of 60

Joins

34 of 60

Simple Join

var filter = ee.Filter.equals({leftField: 'p1', rightField: 'p3'});

var simpleJoin = ee.Join.simple();

var simpleJoined = simpleJoin.apply(primary, secondary, filter);

‘p1’

‘p2’

0

a

1

b

2

c

‘p3’

‘p4’

1

d

2

e

3

f

‘p1’

‘p2’

1

b

2

c

primary

collection

secondary

collection

Join

collection

35 of 60

Inner Join

var filter = ee.Filter.equals({leftField: 'p1', rightField: 'p3'});

var innerJoin = ee.Join.inner('primary', 'secondary');

var toyJoin = innerJoin.apply(primaryFeatures, secondaryFeatures, filter);

‘p1’

‘p2’

0

a

1

b

1

c

2

d

‘p3’

‘p4’

1

e

1

f

2

g

3

h

‘primary’

1

b

1

b

1

c

1

c

2

d

‘secondary’

1

e

1

f

1

e

1

f

2

g

primary

collection

secondary

collection

Join

ee.FeatureCollection

36 of 60

Save All Join

var filter = ee.Filter.equals({leftField: 'p1', rightField: 'p3'});

var saveAllJoin = ee.Join.saveAll('matches');

var toyJoin = saveAllJoin.apply(primary, secondary, filter);

‘p1’

‘p2’

0

a

1

b

2

c

‘p3’

‘p4’

1

d

1

e

2

f

3

g

Join

‘p1’

‘p2’

1

b

2

c

‘p3’

‘p4’

1

d

1

e

‘matches’

‘p3’

‘p4’

2

f

secondary

collection

primary

collection

collection

ee.List

ee.List

37 of 60

Save Best Join

var maxDiffFilter = ee.Filter.maxDifference({

difference: 2*24*60*60*1000, // two days

leftField: 'system:time_start',

rightField: 'system:time_start'

});

var saveBestJoin = ee.Join.saveBest({matchKey: 'bestImage', measureKey: 'timeDiff'});

var joined = saveBestJoin.apply(primary, secondary, maxDiffFilter);

ee.Image

ee.Image

‘bestImage’

ee.Number

‘timeDiff’

primary

collection

secondary

collection

Join

38 of 60

Spatial Join

var spatialFilter = ee.Filter.withinDistance({

distance: 100000,

leftField: '.geo',

rightField: '.geo',

maxError: 10

});

var saveAllJoin = ee.Join.saveAll({

matchesKey: 'scenes',

measureKey: 'distance'

});

var joined = saveAllJoin.apply(california, wrs, spatialFilter);

var list = ee.List(joined.first().get('scenes'));

var scenes = ee.FeatureCollection(list);

39 of 60

Charts

40 of 60

Time series in a region

ui.Chart.image.series(collection, region, ee.Reducer.mean(), 30);

region

ee.ImageCollection

41 of 60

Customizing a Chart

var options = {

title: 'Landsat 8 DN histogram, bands 2-5',

fontSize: 20,

hAxis: {title: 'DN'},

vAxis: {title: 'count of DN'},

series: {

0:{color: 'blue'},

1:{color: 'green'},

2:{color: 'red'},

3:{color: 'magenta'}}

};

var customChart = chart.setOptions(options);

42 of 60

Histogram in a region

var histogram = ui.Chart.image.histogram(image, region, 30)

.setSeriesNames(['blue', 'green', 'red', 'NIR'])

.setOptions(options);

region

ee.Image

43 of 60

Mean spectra in regions

var wavelengths = [0.44, 0.48, 0.56, 0.65, 0.86, 1.61, 2.2];

var spectraChart = ui.Chart.image.regions(

image, regions, ee.Reducer.mean(), 30, 'label', wavelengths)

.setChartType('LineChart')

.setOptions(options);

regions

44 of 60

Time series in regions

var bandName = 'B11';

var temperatureSeries = ui.Chart.image.seriesByRegion(

collection, regions, ee.Reducer.mean(), bandName, 200, 'system:time_start', 'label')

.setOptions(options);

45 of 60

Day-Of-Year (DOY) series in a region

ui.Chart.image.doySeries(collection, region, ee.Reducer.mean(), 500);

46 of 60

DOY series by year

ui.Chart.image.doySeriesByYear(

collection, bandName, region, ee.Reducer.mean(), 500);

47 of 60

DOY series by region

ui.Chart.image.doySeriesByRegion(

collection, bandName, regions, ee.Reducer.mean(), 500, ee.Reducer.mean(), 'label');

48 of 60

Spectra by class band

ui.Chart.image.byClass(

image, classBand, region, ee.Reducer.mean(), 500, classNames, wavelengths)

49 of 60

Scatter chart: band correlation

ui.Chart.array.values(yValues, 0, xValues).setSeriesNames(['B5', 'B6'])

50 of 60

Arrays

51 of 60

What is an Array?

1-axis

0-axis

0

1

2

3

4

5

0

0.3037

0.2793

0.4743

0.5585

0.5082

0.1863

1

-0.2848

-0.2435

-0.5436

0.7243

0.0840

-0.1800

2

0.1509

0.1973

0.3279

0.3406

-0.7112

-0.4572

3

-0.8242

0.0849

0.4392

-0.0580

0.2012

-0.2768

4

-0.3280

0.0549

0.1075

0.1855

-0.4357

0.8085

5

0.1084

-0.9022

0.4120

0.0573

-0.0251

0.0238

ee.Array([

[ 0.3037, 0.2793, 0.4743, 0.5585, 0.5082, 0.1863],

[-0.2848, -0.2435, -0.5436, 0.7243, 0.0840, -0.1800],

[ 0.1509, 0.1973, 0.3279, 0.3406, -0.7112, -0.4572],

[-0.8242, 0.0849, 0.4392, -0.0580, 0.2012, -0.2768],

[-0.3280, 0.0549, 0.1075, 0.1855, -0.4357, 0.8085],

[ 0.1084, -0.9022, 0.4120, 0.0573, -0.0251, 0.0238]

]

52 of 60

Array Dimensions

ee.Array(42); // 0-D (Scalar)

ee.Array([1, 2, 3]); // 1-D array, variation on the 0-axis

ee.Array([[1], [2], [3]]); // 2-D array (3x1), variation on the 0-axis

ee.Array([[1, 2, 3]]); // 2-D array (1x3), variation on the 1-axis

53 of 60

Array Concatenation

0-axis

1-axis

[1,

2,

3]

[1,

2,

3],

[1,

2,

3],

var array1D = ee.Array([1,2,3]);

ee.Array.cat([array1D], 1);

ee.Array.cat(

[array1D, array1D], 1);

54 of 60

Array Images

ee.Image

ee.Image

2

3

1

image.toArray()

ee.Image

image.toArray(1)

ee.Image

[1,2,3]

[1,2,3]

[[1], [2], [3]]

1-D

1-D

2-D

55 of 60

Example: tasseled cap transform

var coefficients = ee.Array([

[0.3037, 0.2793, 0.4743, 0.5585, 0.5082, 0.1863],

[-0.2848, -0.2435, -0.5436, 0.7243, 0.0840, -0.1800],

[0.1509, 0.1973, 0.3279, 0.3406, -0.7112, -0.4572],

[-0.8242, 0.0849, 0.4392, -0.0580, 0.2012, -0.2768],

[-0.3280, 0.0549, 0.1075, 0.1855, -0.4357, 0.8085],

[0.1084, -0.9022, 0.4120, 0.0573, -0.0251, 0.0238]

]);

var image = ee.Image('LT5_L1T_TOA/LT50440342008285PAC01')

.select(['B1', 'B2', 'B3', 'B4', 'B5', 'B7']);

var arrayImage1D = image.toArray(); // []

var arrayImage2D = arrayImage1D.toArray(1); // [[],[],...,[]]

var componentsImage = ee.Image(coefficients)

.matrixMultiply(arrayImage2D) // [[],[],...,[]]

.arrayProject([0]) // []

.arrayFlatten([['brightness', 'greenness', 'wetness', 'fourth', 'fifth', 'sixth']]);

56 of 60

Covariance Arrays

var arrayCollection = collection.map(function(image) {

return image.toArray();

});

var covarianceImage = arrayCollection.reduce(ee.Reducer.covariance());

// 0-axis

var bandNames = [[ 'B2',

'B3'],

['B2','B3']]; // 1-axis

var collCovImage = collCovariance.arrayFlatten(bandNames);

collCovImage: Image (4 bands)

B2_B2: 364.4705810546875

B2_B3: 430.2426452636719

B3_B2: 430.2426452636719

B3_B3: 510.5294189453125

Pixel

1-axis

0-axis

B2

B3

B2

364

430

B3

430

510

57 of 60

Array Image Collections

ee.Image

[ [b1,...,bp],

[b1,...,bp] ]

2-D

imageCollection

.toArray()

Image axis (0)

Band axis (1)

58 of 60

Array based linear modeling

1

t1

sin(t1)

cos(t1)

NDVI1

1

t2

sin(t2)

cos(t2)

NDVI2

1

t3

sin(t3)

cos(t3)

NDVI3

1

tT

sin(tT)

cos(tT)

NDVIT

𝛽0 + 𝛽1t + 𝛽2sin(t) + 𝛽2cos(t) = NDVI

PTx4B4x1 = RTx1

Image axis (0)

0

1

2

3

4

Band axis (1)

slice

59 of 60

Array based linear modeling

var array = collection.toArray();

var imageAxis = 0;

var bandAxis = 1;

var predictors = array.arraySlice(bandAxis, 0, 4);

var response = array.arraySlice(bandAxis, 4);

var coefficients3 = predictors.matrixSolve(response);

60 of 60

code.earthengine.google.com

What will you create with Earth Engine?